GORM入门:事务管理全解析(二)
一、gorm事务
Gorm提供了两种事务实现方案:通过Transaction闭包实现的自动事务管理,以及基于Begin/Commit/Rollback的手动事务控制机制。
Grom默认在事务中执行单个create、update、delete操作,以确保数据库数据完成型性。如果想将多个crete、update、delete操作当作一个操作处理,就需要用到事务。
二、手动事务控制机制实现
在手动事务模式下,需显式调用Rollback和Commit方法,并通过defer语句处理panic异常情况。代码示例如下:
// 需要显示开启事务tx := db.Begin()// 进行异常捕获,进行事务回滚defer func() {if err := recover(); err != nil {tx.Rollback()}}()// 存储信息tx.Create(&User{Name: "王五",Email: "11.com",Age: 29,})// 创建失败,进行事务回滚if tx.Error != nil {tx.Rollback()fmt.Printf("create user1 failed ,%v\n", tx.Error)return}tx.Create(&User{Name: "张三",Email: "qq.com",Age: 19,})// 创建失败,进行事务回滚if tx.Error != nil {tx.Rollback()fmt.Printf("create user2 failed ,%v\n", tx.Error)return}// 提交事务if err := tx.Commit().Error; err != nil {fmt.Printf("commite failed ,%v\n", err)return}
需要显式的调用Begin、Commit、RollBack()等方法实现事务提交和错误回滚。需要注意的是,当调用db.Begin()开启事务后,后续事务处理中使用tx作为数据库句柄,所有操作必须使用同一个事务对象(tx),混用原始数据库对象(db)会导致操作超出事务范围。
三、自动事务管理
在自动事务模式下,闭包内返回错误将触发自动回滚,而返回nil则会自动提交事务。建议使用自动事务管理。代码示例如下:
// 自动事务err := db.Transaction(func(tx *gorm.DB) error {if err := tx.Create(&User{Name: "王五", Email: "11.com", Age: 29}).Error; err != nil {// 返回错误会自动触发回滚return err}if err := tx.Create(&User{Name: "王六", Email: "112.com", Age: 39}).Error; err != nil {// 返回错误会自动触发回滚return err}// 返回nil自动提交事务return nil})
四、自动和手动事务对比
阶段 | 自动事务模式 | 手动事务模式 |
---|---|---|
开启 | Transaction() 闭包 | Begin() |
操作执行 | 使用闭包参数 tx | 使用 Begin() 返回的 tx |
提交/回滚触发 | 闭包返回值控制 | 显式调用 Commit() /Rollback() |
错误处理 | 闭包内返回 error 自动回滚 | 需手动检查错误并回滚 |
五、事务高级功能
1)事务点回滚
GORM 提供了 SavePoint
和 RollbackTo
方法,用于支持事务保存点及回滚到指定保存点的功能。代码示例如下:
tx := db.Begin()tx.Create(&User{Name: "王五", Email: "11.com", Age: 29})tx.SavePoint("sp1")tx.Create(&User{Name: "王六", Email: "112.com", Age: 39})// 回滚到保存点sp1tx.RollbackTo("sp1") // 提交第一用户信息tx.Commit()
从代码中可以看出,当事务回滚到特定保存点时,提交操作只会在保存点之前的数据上生效。
2)事务嵌套
可以在一项主事务中嵌套一个或多个子事务 ,代码示例如下:
db.Transaction(func(tx *gorm.DB) error {tx.Create(&User{Name: "王五", Email: "112.com", Age: 39})tx.Transaction(func(tx2 *gorm.DB) error {tx2.Create(&User{Name: "王六", Email: "112.com", Age: 39})return errors.New("rollback")})tx.Transaction(func(tx3 *gorm.DB) error {tx3.Create(&User{Name: "王七", Email: "112.com", Age: 39})return nil})return nil})