这是我参与「第五届⻘训营 」笔记创作活动的第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
})