• gorm 中的事务运用


    使用背景

    在编写业务代码的过程中,如果涉及到多张表的更新操作,为了确保数据的一致性,我们会在业务代码的过程中加上事务的控制,那么针对go 语言中,如果我们使用gorm框架改如何操作呢?

    gorm中使用事务的几种方式

    • 方式一(业务层事务)
    func NewTransaction() *gorm.DB {
    	return suit.GetGormClient().Begin()
    }
    
    tx := s.AlarmDao.NewTransaction()
    defer tx.Rollback()
    
    ...(具体业务处理)
    
    err = tx.Commit().Error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 方式二(dao层事务)
    func (r *Repo) TxUpdateBonus(ctx context.Context, bonus *entity.Bonus, transaction *entity.Transaction) error {
    	return r.Connection().Transaction(func(tx *gorm.DB) error {
    		if bonus.ID < 1 {
    			if err := tx.WithContext(ctx).Create(bonus).Error; err != nil {
    				return err
    			}
    		} else {
    			if err := tx.WithContext(ctx).Model(bonus).Updates(bonus.Conv2Map()).Error; err != nil {
    				return err
    			}
    		}
    
    		if err := tx.WithContext(ctx).Create(transaction).Error; err != nil {
    			return err
    		}
    		return nil
    	})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 方式三(业务层)
    var dbClient *DbClient
    
    type DbClient struct {
    	MysqlClient *gorm.DB
    }
    
    func NewDbClient() *DbClient {
    	dbClient = &DbClient{}
    	dbClient.MysqlClient = suit.GetGormClient()
    	return dbClient
    }
    
    type contextTxKey struct{}
    
    type TxFn func(context.Context) error
    
    func ExecTx(ctx context.Context, fn TxFn) error {
    	return suit.GetGormClient().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
    		ctx = context.WithValue(ctx, contextTxKey{}, tx)
    		return fn(ctx)
    	})
    }
    
    func GetTxGorm(ctx context.Context) (db *gorm.DB, ok bool) {
    	db, ok = ctx.Value(contextTxKey{}).(*gorm.DB)
    	return
    }
    
    
    err = dao.ExecTx(ctx, func(ctx context.Context) error {
    	instance.DeletedAt = time.Now()
    	instance.UpdatedAt = time.Now()
    	instance.State = constant.InstanceStateDeleteSuccess
    	err = a.MongodbInstance.UpdateOrInsert(ctx, &instance)
    	if err != nil {
    		return err
    	}
    	req := &middleware.DeleteMongoDBDBInstanceRequest{}
    	err = a.MiddlewareClient.DeleteMongoDBDBInstance(ctx, common, req)
    	if err != nil {
    		return err
    	}
    	err = a.deleteAndRefundResource(ctx, &instance, true, false)
    	return err
    })
    
    
    func (a *MongodbInstance) dbClient(ctx context.Context) *gorm.DB {
    	if tx, ok := dao.GetTxGorm(ctx); ok {
    		return tx
    	}
    	return a.DB.MysqlClient
    }
    
    func (a *MongodbInstance) UpdateOrInsert(ctx context.Context, p *po.MongodbInstance) (err error) {
    	client := a.dbClient(ctx)
    	if p.Id == 0 {
    		err = client.Table(po.MongodbInstance{}.TableName()).Create(p).Error
    		return
    	}
    	err = client.Table(po.MongodbInstance{}.TableName()).Select("*").Omit("created_at").Updates(p).Error
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
  • 相关阅读:
    C++ 高性能爬虫
    this.$set用法
    封装自己的本地缓存类(单例模式、适配器模式应用)
    操作系统——文件管理の选择题整理
    基于单片机预费电表控制系统(proteus仿真+源程序)
    InstallAnywhere制作安装包
    flutter 设置全屏 和隐藏状态栏和导航栏
    ChatGPT可以生成Windows密钥
    价值32k!阿里顶级架构师深度解析SpringBoot进阶原理实战手册
    mybatis循环插入
  • 原文地址:https://blog.csdn.net/weixin_47978762/article/details/133895311