fix(server): refactor server model methods to support transaction handling

This commit is contained in:
Chang lue Tsen 2025-05-06 13:21:27 +09:00
parent 38bcacc9e7
commit 3cadd9e621
3 changed files with 32 additions and 33 deletions

View File

@ -2,11 +2,11 @@ package server
import (
"context"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
@ -29,20 +29,23 @@ func NewDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete
func (l *DeleteNodeLogic) DeleteNode(req *types.DeleteNodeRequest) error {
err := l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
// Delete server
err := l.svcCtx.ServerModel.Delete(l.ctx, req.Id)
err := l.svcCtx.ServerModel.Delete(l.ctx, req.Id, tx)
if err != nil {
return err
}
// Delete server to subscribe
subs, err := l.svcCtx.SubscribeModel.QuerySubscribeIdsByServerIdAndServerGroupId(l.ctx, req.Id, 0)
if err != nil {
l.Logger.Errorf("[DeleteNode] QuerySubscribeIdsByServerIdAndServerGroupId error: %v", err.Error())
return err
}
for _, sub := range subs {
servers := tool.StringToInt64Slice(sub.Server)
newServers := tool.RemoveElementBySlice(servers, req.Id)
sub.Server = tool.Int64SliceToString(newServers)
if err = l.svcCtx.SubscribeModel.Update(l.ctx, sub); err != nil {
if err = l.svcCtx.SubscribeModel.Update(l.ctx, sub, tx); err != nil {
l.Logger.Errorf("[DeleteNode] UpdateSubscribe error: %v", err.Error())
return err
}
}

View File

@ -23,10 +23,10 @@ type (
customServerLogicModel
}
serverModel interface {
Insert(ctx context.Context, data *Server) error
Insert(ctx context.Context, data *Server, tx ...*gorm.DB) error
FindOne(ctx context.Context, id int64) (*Server, error)
Update(ctx context.Context, data *Server) error
Delete(ctx context.Context, id int64) error
Update(ctx context.Context, data *Server, tx ...*gorm.DB) error
Delete(ctx context.Context, id int64, tx ...*gorm.DB) error
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
}
@ -77,8 +77,11 @@ func (m *defaultServerModel) getCacheKeys(data *Server) []string {
return cacheKeys
}
func (m *defaultServerModel) Insert(ctx context.Context, data *Server) error {
func (m *defaultServerModel) Insert(ctx context.Context, data *Server, tx ...*gorm.DB) error {
err := m.ExecCtx(ctx, func(conn *gorm.DB) error {
if len(tx) > 0 {
conn = tx[0]
}
return conn.Create(&data).Error
}, m.getCacheKeys(data)...)
return err
@ -98,19 +101,21 @@ func (m *defaultServerModel) FindOne(ctx context.Context, id int64) (*Server, er
}
}
func (m *defaultServerModel) Update(ctx context.Context, data *Server) error {
func (m *defaultServerModel) Update(ctx context.Context, data *Server, tx ...*gorm.DB) error {
old, err := m.FindOne(ctx, data.Id)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
err = m.ExecCtx(ctx, func(conn *gorm.DB) error {
db := conn
return db.Save(data).Error
if len(tx) > 0 {
conn = tx[0]
}
return conn.Save(data).Error
}, m.getCacheKeys(old)...)
return err
}
func (m *defaultServerModel) Delete(ctx context.Context, id int64) error {
func (m *defaultServerModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) error {
data, err := m.FindOne(ctx, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
@ -119,8 +124,10 @@ func (m *defaultServerModel) Delete(ctx context.Context, id int64) error {
return err
}
err = m.ExecCtx(ctx, func(conn *gorm.DB) error {
db := conn
return db.Delete(&Server{}, id).Error
if len(tx) > 0 {
conn = tx[0]
}
return conn.Delete(&Server{}, id).Error
}, m.getCacheKeys(data)...)
return err
}

View File

@ -52,33 +52,26 @@ func (*Server) TableName() string {
func (s *Server) BeforeDelete(tx *gorm.DB) error {
logger.Debugf("[Server] BeforeDelete")
if err := tx.Exec("UPDATE `server` SET sort = sort - 1 WHERE sort > ?", s.Sort).Error; err != nil {
return err
}
// 删除后重新排序,防止因 sort 缺口导致问题
if err := reorderSort(tx); err != nil {
return err
}
return nil
}
func (s *Server) BeforeUpdate(tx *gorm.DB) error {
logger.Debugf("[Server] BeforeUpdate")
var count int64
if err := tx.Model(&Server{}).Where("sort = ? AND id != ?", s.Sort, s.Id).Count(&count).Error; err != nil {
if err := tx.Set("gorm:query_option", "FOR UPDATE").Model(&Server{}).
Where("sort = ? AND id != ?", s.Sort, s.Id).Count(&count).Error; err != nil {
return err
}
if count > 0 {
logger.Debugf("[Server] Duplicate sort found, reordering...")
if err := reorderSort(tx); err != nil {
var maxSort int64
if err := tx.Model(&Server{}).Select("MAX(sort)").Scan(&maxSort).Error; err != nil {
return err
}
s.Sort = maxSort + 1
}
return nil
}
@ -191,17 +184,13 @@ func (RuleGroup) TableName() string {
}
func reorderSort(tx *gorm.DB) error {
var servers []*Server
if err := tx.Model(&Server{}).Order("sort ASC").Find(&servers).Error; err != nil {
var servers []Server
if err := tx.Order("sort, id").Find(&servers).Error; err != nil {
return err
}
for i, server := range servers {
newSort := int64(i + 1)
if server.Sort != newSort {
if err := tx.Model(&Server{}).
Where("id = ?", server.Id).
Update("sort", newSort).Error; err != nil {
if server.Sort != int64(i)+1 {
if err := tx.Exec("UPDATE `server` SET sort = ? WHERE id = ?", i+1, server.Id).Error; err != nil {
return err
}
}