diff --git a/mayfly_go_web/package.json b/mayfly_go_web/package.json index b44e3461..a7172fa4 100644 --- a/mayfly_go_web/package.json +++ b/mayfly_go_web/package.json @@ -28,8 +28,8 @@ "monaco-sql-languages": "^0.12.2", "monaco-themes": "^0.4.4", "nprogress": "^0.2.0", - "pinia": "^2.2.4", - "qrcode.vue": "^3.5.0", + "pinia": "^2.2.5", + "qrcode.vue": "^3.5.1", "screenfull": "^6.0.2", "sortablejs": "^1.15.3", "splitpanes": "^3.1.5", @@ -58,7 +58,7 @@ "eslint": "^8.35.0", "eslint-plugin-vue": "^9.28.0", "prettier": "^3.2.5", - "sass": "^1.80.3", + "sass": "^1.80.5", "typescript": "^5.6.3", "vite": "^5.4.10", "vue-eslint-parser": "^9.4.3" diff --git a/server/pkg/base/app.go b/server/pkg/base/app.go index 58c1a831..01254480 100644 --- a/server/pkg/base/app.go +++ b/server/pkg/base/app.go @@ -160,27 +160,46 @@ func (ai *AppImpl[T, R]) CountByCond(cond any) int64 { return ai.GetRepo().CountByCond(cond) } -// 执行事务操作 +// Tx 执行事务操作 func (ai *AppImpl[T, R]) Tx(ctx context.Context, funcs ...func(context.Context) error) (err error) { - tx := global.Db.Begin() - dbCtx := contextx.WithDb(ctx, tx) + tx := contextx.GetTx(ctx) + dbCtx := ctx + var txDb *gorm.DB + + if tx == nil { + txDb = global.Db.Begin() + dbCtx, tx = contextx.WithTxDb(ctx, txDb) + } else { + txDb = tx.DB + tx.Count++ + } defer func() { - // 移除当前已执行完成的的数据库事务实例 - contextx.RmDb(ctx) if r := recover(); r != nil { - tx.Rollback() - err = fmt.Errorf("%v", err) + txDb.Rollback() + contextx.RmDb(ctx) + err = fmt.Errorf("%v", r) + return + } + + tx.Count-- + if tx.Count < 1 { + // 移除当前已执行完成的的数据库事务实例 + contextx.RmDb(ctx) } }() for _, f := range funcs { err = f(dbCtx) if err != nil { - tx.Rollback() + tx.Count = 0 + txDb.Rollback() return } } - err = tx.Commit().Error + + if tx.Count == 1 { + err = txDb.Commit().Error + } return } diff --git a/server/pkg/contextx/contextx.go b/server/pkg/contextx/contextx.go index c51f9331..2085ce10 100644 --- a/server/pkg/contextx/contextx.go +++ b/server/pkg/contextx/contextx.go @@ -49,28 +49,56 @@ func GetTraceId(ctx context.Context) string { return "" } -// 将事务db放置context中,使用stack保存。以便多个方法调用实现方法内部各自的事务操作 -func WithDb(ctx context.Context, db *gorm.DB) context.Context { - if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok { - dbStack.Push(db) - return ctx - } - dbStack := new(collx.Stack[*gorm.DB]) - dbStack.Push(db) - - return context.WithValue(ctx, DbKey, dbStack) +// Tx 事务上下文信息 +type Tx struct { + Count int + DB *gorm.DB } -// 获取当前操作的栈顶事务数据库实例 +func (t *Tx) Rollback() { + if t.Count == 0 { + t.DB.Rollback() + } else { + + } +} + +// WithTxDb 将事务db放置context中,使用stack保存。以便多个方法调用实现方法内部各自的事务操作 +func WithTxDb(ctx context.Context, db *gorm.DB) (context.Context, *Tx) { + tx := &Tx{Count: 1, DB: db} + if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*Tx]); ok { + dbStack.Push(tx) + return ctx, tx + } + dbStack := new(collx.Stack[*Tx]) + dbStack.Push(tx) + + return context.WithValue(ctx, DbKey, dbStack), tx +} + +// GetDb 获取当前操作的栈顶事务数据库实例 func GetDb(ctx context.Context) *gorm.DB { - if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok { - return dbStack.Top() + if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*Tx]); ok { + if tx := dbStack.Top(); tx != nil { + return tx.DB + } } return nil } -func RmDb(ctx context.Context) *gorm.DB { - if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok { +// GetTx 获取当前操作的栈顶事务信息 +func GetTx(ctx context.Context) *Tx { + if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*Tx]); ok { + if tx := dbStack.Top(); tx != nil { + return tx + } + } + return nil +} + +// RmDb 删除数据库事务db +func RmDb(ctx context.Context) *Tx { + if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*Tx]); ok { return dbStack.Pop() } return nil