GORM 事务支持 | ⻘训营笔记

442 阅读2分钟

这是我参与「第五届⻘训营 」笔记创作活动的第20天。

项目中使用了gorm作为数据库查询使用orm框架,加上在课程的学习中了解到了数据库ACID特性,所以想把项目中的数据操作部分改为使用事务实现,能提高项目的安全性。

事务ACID属性

数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

举一个简单的例子,转账。A 转账给 B 一万元,那么数据库至少需要执行 2 个操作:

  • 1)A 的账户减掉一万元。
  • 2)B 的账户增加一万元。

这两个操作要么全部执行,代表转账成功。任意一个操作失败了,之前的操作都必须回退,代表转账失败。一个操作完成,另一个操作失败,这种结果是不能够接受的。这种场景就非常适合利用数据库事务的特性来解决。

如果一个数据库支持事务,那么必须具备 ACID 四个属性。

  • 1)原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
  • 2)一致性(Consistency): 几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。
  • 3)隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
  • 4)持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

GORM中的事务

由于事务本身的属性势造成性能下降,如果没有事务要求,可以手动关闭,会提升30%性能。

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

下面是使用GORM事务的示例代码。

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