package gormExample import ( "errors" "gorm.io/gorm" "log" ) func TXDemo() { // 初始化测试数据 if err := DB.AutoMigrate(&Author{}); err != nil { log.Fatalln(err) } var a1, a2 Author a1.Name = "库里" a2.Name = "莫兰特" a1.Points = 11600 a2.Points = 200 if err := DB.Create([]*Author{&a1, &a2}).Error; err != nil { log.Fatalln(err) } // 事务操作 // a1 赠送 a2 2000 积分 p := 2000 // 开始事务 tx := DB.Begin() // 有时需要考虑数据库是否支持事务的情景 if tx.Error != nil { log.Fatalln(tx.Error) } // 执行赠送操作 a1.Points -= p a2.Points += p // 1执行SQL,可能导致的错误 if err := tx.Save(&a1).Error; err != nil { tx.Rollback() return } if err := tx.Save(&a2).Error; err != nil { // 回滚事务 tx.Rollback() return } // 2业务逻辑可能导致的错误 // 要求author的积分不能为负数 if a1.Points < 0 || a2.Points < 0 { log.Println("a1.Points < 0 || a2.Points < 0") // 回滚事务 if err := tx.Rollback().Error; err != nil { log.Fatalln(err) } } // 提交事务 if err := tx.Commit().Error; err != nil { log.Fatalln(err) } // 决定回滚还是提交,集中的处理错误风格 //if err1 != nil || err2 != nil { // tx.Rollback() //} else { // tx.Commit() //} } func TXCallback() { // 初始化测试数据 if err := DB.AutoMigrate(&Author{}); err != nil { log.Fatalln(err) } var a1, a2 Author a1.Name = "库里" a2.Name = "莫兰特" a1.Points = 1600 a2.Points = 200 if err := DB.Create([]*Author{&a1, &a2}).Error; err != nil { log.Fatalln(err) } log.Println(a1.ID, a2.ID) // 实现事务 if err := DB.Transaction(func(tx *gorm.DB) error { // a1 赠送 a2 2000 积分 p := 200 // 执行赠送操作 a1.Points -= p a2.Points += p // 1执行SQL,可能导致的错误 if err := tx.Save(&a1).Error; err != nil { return err } if err := tx.Save(&a2).Error; err != nil { return err } // 2业务逻辑可能导致的错误 // 要求author的积分不能为负数 if a1.Points < 0 || a2.Points < 0 { return errors.New("a1.Points < 0 || a2.Points < 0") } // nil 的返回,会导致事务提交 return nil }); err != nil { // 返回错误,为了后续的业务逻辑处理 // 为了通知我们,事务成功还是失败 // 返回错误,不影响事务的提交和回滚 log.Println(err) } } func TXNested() { // 初始化测试数据 if err := DB.AutoMigrate(&Author{}); err != nil { log.Fatalln(err) } var a1, a2, a3 Author a1.Name = "库里" a2.Name = "莫兰特" a3.Name = "欧文" a1.Points = 1600 a2.Points = 200 a3.Points = 4000 if err := DB.Create([]*Author{&a1, &a2, &a3}).Error; err != nil { log.Fatalln(err) } log.Println(a1.ID, a2.ID, a3.ID) // 实现事务 if err := DB.Transaction(func(tx *gorm.DB) error { // a1 赠送 a2 2000 积分 p := 20000 // 执行赠送操作 // a2 多了积分 a2.Points += p if err := tx.Save(&a2).Error; err != nil { return err } // a1 赠送,使用嵌套事务完成 errA1 := tx.Transaction(func(tx *gorm.DB) error { a1.Points -= p // 1执行SQL,可能导致的错误 if err := tx.Save(&a1).Error; err != nil { return err } if a1.Points < 0 { return errors.New("a1.Points < 0") } // 没有错误成功 return nil }) // a1 发送失败,才需要a3 if errA1 != nil { // a3 赠送,使用嵌套事务完成 errA3 := DB.Transaction(func(tx *gorm.DB) error { a3.Points -= p if err := tx.Save(&a3).Error; err != nil { return err } if a3.Points < 0 { return errors.New("a3.Points < 0") } return nil }) // a3 同样失败 if errA3 != nil { return errors.New("a1 and a3 all send points failed") } } // nil 的返回,会导致事务提交 return nil }); err != nil { // 返回错误,为了后续的业务逻辑处理 // 为了通知我们,事务成功还是失败 // 返回错误,不影响事务的提交和回滚 log.Println(err) } } func TXSavePoint() { // 初始化测试数据 if err := DB.AutoMigrate(&Author{}); err != nil { log.Fatalln(err) } var a1, a2, a3 Author a1.Name = "库里" a2.Name = "莫兰特" a3.Name = "欧文" a1.Points = 1600 a2.Points = 200 a3.Points = 4000 if err := DB.Create([]*Author{&a1, &a2, &a3}).Error; err != nil { log.Fatalln(err) } log.Println(a1.ID, a2.ID, a3.ID) // 事务操作 // a1 赠送 a2 2000 积分 p := 20000 // 开始事务 tx := DB.Begin() // 有时需要考虑数据库是否支持事务的情景 if tx.Error != nil { log.Fatalln(tx.Error) } // 执行赠送操作 // a2 得到积分 a2.Points += p // 1执行SQL,可能导致的错误 if err := tx.Save(&a2).Error; err != nil { tx.Rollback() return } // 逻辑记录发送points是否成功 var flagSend bool // a1 先给 a2 send // 设置一个 savepoint tx.SavePoint("beforeA1") a1.Points -= p if err := tx.Save(&a1).Error; err != nil || a1.Points < 0 { // 回滚到 beforeA1 tx.RollbackTo("beforeA1") // a3 to a2 tx.SavePoint("beforeA3") a3.Points -= p if err := tx.Save(&a3).Error; err != nil || a3.Points < 0 { // 回滚到 beforeA3 tx.RollbackTo("beforeA3") } else { flagSend = true } } else { flagSend = true } // 判定发送是否成功 if flagSend { // 提交事务 if err := tx.Commit().Error; err != nil { log.Fatalln(err) } } else { // 回滚事务 tx.Rollback() } }