禁用默认事务

为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。

  1. // 全局禁用
  2. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  3. SkipDefaultTransaction: true,
  4. })
  5. // 持续会话模式
  6. tx := db.Session(&Session{SkipDefaultTransaction: true})
  7. tx.First(&user, 1)
  8. tx.Find(&users)
  9. tx.Model(&user).Update("Age", 18)

事务

要在事务中执行一系列操作,一般流程如下:

  1. db.Transaction(func(tx *gorm.DB) error {
  2. // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
  3. if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
  4. // 返回任何错误都会回滚事务
  5. return err
  6. }
  7. if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
  8. return err
  9. }
  10. // 返回 nil 提交事务
  11. return nil
  12. })

嵌套事务

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

  1. DB.Transaction(func(tx *gorm.DB) error {
  2. tx.Create(&user1)
  3. tx.Transaction(func(tx2 *gorm.DB) error {
  4. tx2.Create(&user2)
  5. return errors.New("rollback user2") // Rollback user2
  6. })
  7. tx.Transaction(func(tx2 *gorm.DB) error {
  8. tx2.Create(&user3)
  9. return nil
  10. })
  11. return nil
  12. })
  13. // Commit user1, user3

手动事务

  1. // 开始事务
  2. tx := db.Begin()
  3. // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
  4. tx.Create(...)
  5. // ...
  6. // 遇到错误时回滚事务
  7. tx.Rollback()
  8. // 否则,提交事务
  9. tx.Commit()

一个特殊的示例

  1. func CreateAnimals(db *gorm.DB) error {
  2. // 再唠叨一下,事务一旦开始,你就应该使用 tx 处理数据
  3. tx := db.Begin()
  4. defer func() {
  5. if r := recover(); r != nil {
  6. tx.Rollback()
  7. }
  8. }()
  9. if err := tx.Error; err != nil {
  10. return err
  11. }
  12. if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
  13. tx.Rollback()
  14. return err
  15. }
  16. if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
  17. tx.Rollback()
  18. return err
  19. }
  20. return tx.Commit().Error
  21. }

SavePoint、RollbackTo

GORM 提供了 SavePointRollbackto 来提供保存点以及回滚至保存点,例如:

  1. tx := DB.Begin()
  2. tx.Create(&user1)
  3. tx.SavePoint("sp1")
  4. tx.Create(&user2)
  5. tx.RollbackTo("sp1") // 回滚 user2
  6. tx.Commit() // 最终仅提交 user1