如何優雅的使用 GORM 來實現 MySQL 事務
theme: awesome-green
我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第2篇文章,點擊查看活動詳情
前言
為了確保數據一致性,在項目中會經常用到事務處理,回滾操作還是比較常見的需求;事務處理可以用來維護數據庫的完整性,保證成批的sql語句要麼全部都執行,要麼全不執行,對於MySQL事務相信大家應該都不陌生,這篇文章主要總結一下在Go語言中Gorm是如何實現事務的;感興趣的小夥伴們可以參考借鑑,希望對大家能有所幫助。
禁用默認事務
gorm事務默認是開啟的。為了確保數據一致性,Gorm會在事務裏執行寫入操作(增刪改)。
如果對數據一致性要求不高的話,可以在初始化時禁用它,性能將提升大約30%。
一般不推薦禁用。
// 全局禁用
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
SkipDefaultTransaction: true,
})
自動事務
通過db.Transaction函數實現事務,如果閉包函數返回錯誤,則回滾事務。
``` db.Transaction(func(tx *gorm.DB) error { // 在事務中執行一些 db 操作(從這裏開始,您應該使用 'tx' 而不是 'db') if err := tx.Create(&User{Name: "Lili"}).Error; err != nil { // 返回任何錯誤都會回滾事務 return err }
if err := tx.Create(&User{Name: "xiaoming"}).Error; err != nil { return err }
// 返回 nil 提交事務 return nil }) ```
手動事務
在開發中經常需要數據庫事務來保證多個數據庫寫操作的原子性。例如電商系統中的扣減庫存和保存訂單。
gorm事務用法:
``` // 開啟事務 tx := db.Begin()
//在事務中執行數據庫操作,使用的是tx變量,不是db。
//庫存減一
//等價於: UPDATE goods
SET stock
= stock - 1 WHERE goods
.id
= '2' and stock > 0
//RowsAffected用於返回sql執行後影響的行數
rowsAffected := tx.Model(&goods).Where("stock > 0").Update("stock", gorm.Expr("stock - 1")).RowsAffected
if rowsAffected == 0 {
//如果更新庫存操作,返回影響行數為0,説明沒有庫存了,結束下單流程
//這裏回滾作用不大,因為前面沒成功執行什麼數據庫更新操作,也沒什麼數據需要回滾。
//這裏就是舉個例子,事務中可以執行多個sql語句,錯誤了可以回滾事務
tx.Rollback()
return
}
err := tx.Create(保存訂單).Error
//保存訂單失敗,則回滾事務 if err != nil { tx.Rollback() } else { tx.Commit() } ```
嵌套事務
GORM 支持嵌套事務,可以回滾較大事務內執行的一部分操作,例如:
``` db.Transaction(func(tx *gorm.DB) error { tx.Create(&user1)
tx.Transaction(func(tx2 *gorm.DB) error { tx2.Create(&user2) return errors.New("rollback user2") // Rollback user2 })
tx.Transaction(func(tx2 *gorm.DB) error { tx2.Create(&user3) return nil })
return nil })
// Commit user1, user3 ```
SavePoint、RollbackTo
GORM 提供了 SavePoint、Rollbackto 來提供保存點以及回滾至保存點,例如:
``` tx := db.Begin() tx.Create(&user1)
tx.SavePoint("sp1") tx.Create(&user2) tx.RollbackTo("sp1") // Rollback user2
tx.Commit() // Commit user1 ```
這裏rollback到了sp1的位置,也就是説,數據庫中只存了user1這條數據。
小結
關於Go GORM 事務詳細介紹的文章就介紹到這了,總的來説Gorm事務的實現非常簡單,go語言操作mysql事務主要用到了三個函數:
- Db.Begin() 開始事務
- Db.Commit() 提交事務
- Db.Rollback() 回滾事務