From 3cadd9e62169aabff4f4a4b89cef5cba29798c73 Mon Sep 17 00:00:00 2001 From: Chang lue Tsen Date: Tue, 6 May 2025 13:21:27 +0900 Subject: [PATCH] fix(server): refactor server model methods to support transaction handling --- .../logic/admin/server/deleteNodeLogic.go | 9 ++++-- internal/model/server/default.go | 27 ++++++++++------- internal/model/server/server.go | 29 ++++++------------- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/internal/logic/admin/server/deleteNodeLogic.go b/internal/logic/admin/server/deleteNodeLogic.go index 79d101b..cd4e4c6 100644 --- a/internal/logic/admin/server/deleteNodeLogic.go +++ b/internal/logic/admin/server/deleteNodeLogic.go @@ -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 } } diff --git a/internal/model/server/default.go b/internal/model/server/default.go index abb581c..eecf193 100644 --- a/internal/model/server/default.go +++ b/internal/model/server/default.go @@ -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 } diff --git a/internal/model/server/server.go b/internal/model/server/server.go index bdbae76..8992116 100644 --- a/internal/model/server/server.go +++ b/internal/model/server/server.go @@ -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 } }