mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	fix: 数据库实例删除,事务问题
This commit is contained in:
		@@ -28,8 +28,8 @@
 | 
				
			|||||||
      "monaco-sql-languages": "^0.12.2",
 | 
					      "monaco-sql-languages": "^0.12.2",
 | 
				
			||||||
      "monaco-themes": "^0.4.4",
 | 
					      "monaco-themes": "^0.4.4",
 | 
				
			||||||
      "nprogress": "^0.2.0",
 | 
					      "nprogress": "^0.2.0",
 | 
				
			||||||
      "pinia": "^2.2.4",
 | 
					      "pinia": "^2.2.5",
 | 
				
			||||||
      "qrcode.vue": "^3.5.0",
 | 
					      "qrcode.vue": "^3.5.1",
 | 
				
			||||||
      "screenfull": "^6.0.2",
 | 
					      "screenfull": "^6.0.2",
 | 
				
			||||||
      "sortablejs": "^1.15.3",
 | 
					      "sortablejs": "^1.15.3",
 | 
				
			||||||
      "splitpanes": "^3.1.5",
 | 
					      "splitpanes": "^3.1.5",
 | 
				
			||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
      "eslint": "^8.35.0",
 | 
					      "eslint": "^8.35.0",
 | 
				
			||||||
      "eslint-plugin-vue": "^9.28.0",
 | 
					      "eslint-plugin-vue": "^9.28.0",
 | 
				
			||||||
      "prettier": "^3.2.5",
 | 
					      "prettier": "^3.2.5",
 | 
				
			||||||
      "sass": "^1.80.3",
 | 
					      "sass": "^1.80.5",
 | 
				
			||||||
      "typescript": "^5.6.3",
 | 
					      "typescript": "^5.6.3",
 | 
				
			||||||
      "vite": "^5.4.10",
 | 
					      "vite": "^5.4.10",
 | 
				
			||||||
      "vue-eslint-parser": "^9.4.3"
 | 
					      "vue-eslint-parser": "^9.4.3"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,27 +160,46 @@ func (ai *AppImpl[T, R]) CountByCond(cond any) int64 {
 | 
				
			|||||||
	return ai.GetRepo().CountByCond(cond)
 | 
						return ai.GetRepo().CountByCond(cond)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 执行事务操作
 | 
					// Tx 执行事务操作
 | 
				
			||||||
func (ai *AppImpl[T, R]) Tx(ctx context.Context, funcs ...func(context.Context) error) (err error) {
 | 
					func (ai *AppImpl[T, R]) Tx(ctx context.Context, funcs ...func(context.Context) error) (err error) {
 | 
				
			||||||
	tx := global.Db.Begin()
 | 
						tx := contextx.GetTx(ctx)
 | 
				
			||||||
	dbCtx := contextx.WithDb(ctx, tx)
 | 
						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() {
 | 
						defer func() {
 | 
				
			||||||
		// 移除当前已执行完成的的数据库事务实例
 | 
					 | 
				
			||||||
		contextx.RmDb(ctx)
 | 
					 | 
				
			||||||
		if r := recover(); r != nil {
 | 
							if r := recover(); r != nil {
 | 
				
			||||||
			tx.Rollback()
 | 
								txDb.Rollback()
 | 
				
			||||||
			err = fmt.Errorf("%v", err)
 | 
								contextx.RmDb(ctx)
 | 
				
			||||||
 | 
								err = fmt.Errorf("%v", r)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tx.Count--
 | 
				
			||||||
 | 
							if tx.Count < 1 {
 | 
				
			||||||
 | 
								// 移除当前已执行完成的的数据库事务实例
 | 
				
			||||||
 | 
								contextx.RmDb(ctx)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, f := range funcs {
 | 
						for _, f := range funcs {
 | 
				
			||||||
		err = f(dbCtx)
 | 
							err = f(dbCtx)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			tx.Rollback()
 | 
								tx.Count = 0
 | 
				
			||||||
 | 
								txDb.Rollback()
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = tx.Commit().Error
 | 
					
 | 
				
			||||||
 | 
						if tx.Count == 1 {
 | 
				
			||||||
 | 
							err = txDb.Commit().Error
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,28 +49,56 @@ func GetTraceId(ctx context.Context) string {
 | 
				
			|||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 将事务db放置context中,使用stack保存。以便多个方法调用实现方法内部各自的事务操作
 | 
					// Tx 事务上下文信息
 | 
				
			||||||
func WithDb(ctx context.Context, db *gorm.DB) context.Context {
 | 
					type Tx struct {
 | 
				
			||||||
	if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok {
 | 
						Count int
 | 
				
			||||||
		dbStack.Push(db)
 | 
						DB    *gorm.DB
 | 
				
			||||||
		return ctx
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dbStack := new(collx.Stack[*gorm.DB])
 | 
					 | 
				
			||||||
	dbStack.Push(db)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return context.WithValue(ctx, DbKey, dbStack)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取当前操作的栈顶事务数据库实例
 | 
					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 {
 | 
					func GetDb(ctx context.Context) *gorm.DB {
 | 
				
			||||||
	if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok {
 | 
						if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*Tx]); ok {
 | 
				
			||||||
		return dbStack.Top()
 | 
							if tx := dbStack.Top(); tx != nil {
 | 
				
			||||||
 | 
								return tx.DB
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RmDb(ctx context.Context) *gorm.DB {
 | 
					// GetTx 获取当前操作的栈顶事务信息
 | 
				
			||||||
	if dbStack, ok := ctx.Value(DbKey).(*collx.Stack[*gorm.DB]); ok {
 | 
					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 dbStack.Pop()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user