gorm 事务的使用

gorm事务默认是开启的。为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。

如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。

一般不推荐禁用

// 全局禁用
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  SkipDefaultTransaction: true,
})

普通事务

type TMG struct {
	ID   uint
	Name string
}

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})

	db.Transaction(func(tx *gorm.DB) error {
		// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
		if err := tx.Create(&TMG{Name: "Giraffe"}).Error; err != nil {
			// 返回任何错误都会回滚事务
			return err
		}

		if err := tx.Create(&TMG{Name: "Lion"}).Error; err != nil {
			return err
		}

		// 返回 nil 提交事务
		return nil
	})
}

执行下面代码,其中执行返回了一个test for err的错误,此时事务自动回滚,数据表中无数据
在这里插入图片描述

type TMG struct {
	ID   uint
	Name string
}

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})
	flag := false
	err := db.Transaction(func(tx *gorm.DB) error {
		// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
		if err := tx.Create(&TMG{Name: "Giraffe"}).Error; err != nil {
			// 返回任何错误都会回滚事务
			return err
		}
		if !flag {
			return errors.New("test for err")
		}
		if err := tx.Create(&TMG{Name: "Lion"}).Error; err != nil {
			return err
		}
		// 返回 nil 提交事务
		return nil
	})
	if err != nil {
		fmt.Println(err)//test for err
	}
}

嵌套事务

GORM 支持嵌套事务,您可以回滚较大事务内执行的一部分操作,例如:

在下面代码中,我们知道包含name2的事务返回了err,是会回滚的,而外层事务返回nil,则会提交
在这里插入图片描述

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})
	db.Transaction(func(tx *gorm.DB) error {
		tx.Create(&TMG{Name: "name 1"})

		tx.Transaction(func(tx2 *gorm.DB) error {
			tx2.Create(&TMG{Name: "name 2"})
			return errors.New("rollback user2") // Rollback user2
		})

		tx.Transaction(func(tx2 *gorm.DB) error {
			tx2.Create(&TMG{Name: "name 3"})
			return nil
		})
		return nil
	})
}

手动事务

在这里插入图片描述

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})
	// 开始事务
	tx := db.Begin()

	// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
	tx.Create(&TMG{Name: "wxf1"})
	tx.Create(&TMG{Name: "wxf2"})
	tx.Create(&TMG{Name: "wxf3"})
	// ...

	...
	if err!=nil{
		// 遇到错误时回滚事务
		fmt.Println(tx.Rollback().Error)
	}
	...
	
	// 否则,提交事务
	fmt.Println(tx.Commit().Error)
}

一个特殊的示例

type TMG struct {
	ID   uint
	Name string
}

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})
	// 事务
	CreateTMG(db)

}
func CreateTMG(db *gorm.DB) error {
	// 再唠叨一下,事务一旦开始,你就应该使用 tx 处理数据
	tx := db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	if err := tx.Error; err != nil {
		return err
	}

	if err := tx.Create(&TMG{Name: "Giraffe"}).Error; err != nil {
		tx.Rollback()
		return err
	}

	if err := tx.Create(&TMG{Name: "Lion"}).Error; err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}

SavePoint、RollbackTo

在这里插入图片描述

GORM 提供了 SavePoint、Rollbackto 方法,来提供保存点以及回滚至保存点功能

这里rollback到了sp1的位置,也就是说,数据库中只存了wxf666这条数据

func main() {
	db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
	db.AutoMigrate(&TMG{})
	// 事务
	tx := db.Begin()
	tx.Create(&TMG{Name: "wxf666"})
	tx.SavePoint("sp1")
	
	tx.Create(&TMG{Name: "wxf777"})
	tx.Create(&TMG{Name: "wxf888"})
	tx.SavePoint("sp2")
	
	tx.RollbackTo("sp1")
	tx.Commit()
}
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cheems~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值