本文中作者展示了golang事務的三種寫法。
第一種寫法
這種寫法非常樸實,程序流程也非常明確,但是事務處理與程序流程嵌入太深,容易遺漏,造成嚴重的問題
funcDoSomething()(errerror){
tx,err:=db.Begin()
iferr!=nil{
return
}
deferfunc(){
ifp:=recover();p!=nil{
tx.Rollback()
panic(p)//re-throwpanicafterRollback
}
}()
if_,err=tx.Exec(...);err!=nil{
tx.Rollback()
return
}
if_,err=tx.Exec(...);err!=nil{
tx.Rollback()
return
}
//...
err=tx.Commit()
return
}
第二種寫法
下面這種寫法把事務處理從程序流程抽離了出來,不容易遺漏,但是作用域是整個函數,程序流程不是很清晰
funcDoSomething()(errerror){
tx,err:=db.Begin()
iferr!=nil{
return
}
deferfunc(){
ifp:=recover();p!=nil{
tx.Rollback()
panic(p)//re-throwpanicafterRollback
}elseiferr!=nil{
tx.Rollback()
}else{
err=tx.Commit()
}
}()
if_,err=tx.Exec(...);err!=nil{
return
}
if_,err=tx.Exec(...);err!=nil{
return
}
//...
return
}
第三種寫法
寫法三是對寫法二的進一步封裝,寫法高級一點,缺點同上
funcTransact(db*sql.DB,txFuncfunc(*sql.Tx)error)(errerror){
tx,err:=db.Begin()
iferr!=nil{
return
}
deferfunc(){
ifp:=recover();p!=nil{
tx.Rollback()
panic(p)//re-throwpanicafterRollback
}elseiferr!=nil{
tx.Rollback()
}else{
err=tx.Commit()
}
}()
err=txFunc(tx)
returnerr
}
funcDoSomething()error{
returnTransact(db,func(tx*sql.Tx)error{
if_,err:=tx.Exec(...);err!=nil{
returnerr
}
if_,err:=tx.Exec(...);err!=nil{
returnerr
}
})
}
我的寫法
經過總結和實驗,我采用了下面這種寫法,defer tx.Rollback() 使得事務回滾始終得到執行。當 tx.Commit() 執行后,tx.Rollback() 起到關閉事務的作用, 當程序因為某個錯誤中止,tx.Rollback() 起到回滾事務,同事關閉事務的作用。
普通場景
funcDoSomething()(errerror){
tx,_:=db.Begin()
defertx.Rollback()
if_,err=tx.Exec(...);err!=nil{
return
}
if_,err=tx.Exec(...);err!=nil{
return
}
//...
err=tx.Commit()
return
}
循環場景
(1) 小事務 每次循環提交一次 在循環內部使用這種寫法的時候,defer 不能使用,所以要把事務部分抽離到獨立的函數當中
funcDoSomething()(errerror){
tx,_:=db.Begin()
defertx.Rollback()
if_,err=tx.Exec(...);err!=nil{
return
}
if_,err=tx.Exec(...);err!=nil{
return
}
//...
err=tx.Commit()
return
}
for{
iferr:=DoSomething();err!=nil{
//...
}
}
(2) 大事務 批量提交 大事務的場景和普通場景是一樣的,沒有任何區別
funcDoSomething()(errerror){
tx,_:=db.Begin()
defertx.Rollback()
for{
if_,err=tx.Exec(...);err!=nil{
return
}
if_,err=tx.Exec(...);err!=nil{
return
}
//...
}
err=tx.Commit()
return
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
封裝
+關注
關注
128文章
9248瀏覽量
148605 -
程序
+關注
關注
117文章
3846瀏覽量
85225 -
函數
+關注
關注
3文章
4417瀏覽量
67499
原文標題:Golang transaction 事務使用的正確姿勢
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
【科普】三種電磁屏蔽的目的及原理詳解
電磁屏蔽一般可分為三種:靜電屏蔽、靜磁屏蔽和高頻電磁場屏蔽。三種屏蔽的目的都是防止外界的電磁場進入到某個需要保護的區域中,原理都是利用屏蔽對外場的感應產生的效應來抵消外場的影響。但是由于所要屏蔽的場的特性不同,因而對屏蔽殼材料的要求和屏蔽效果也就不相同。
發表于 09-29 11:21
?5w次閱讀
STM32的三種boot模式介紹
淺識STM32的三種boot模式文章目錄淺識STM32的三種boot模式任務摘要一、認識boot1.三種BOOT模式介紹2.開發BOOT模式選擇3.STM32三種啟動模式4.
發表于 12-10 07:46
三種不同的“防 Ping”技巧
三種不同的“防 Ping”技巧
淺析三種不同的“防 Ping”方法
眾所周知,Ping命令是一個非常有用的網絡命令,大家常用它
發表于 04-14 13:53
?1326次閱讀
PCB常見的三種鉆孔詳解資料下載
電子發燒友網為你提供PCB常見的三種鉆孔詳解資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
發表于 04-18 08:45
?22次下載
MySQL三種日志講解
MySQL 日志包含了錯誤日志、查詢日志、慢查詢日志、事務日志、二進制日志等,如果存儲引擎使用的是 InnoDB ,二進制日志(binlog)和事務日志(包括redo log和undo log) 是肯定繞不過去的,本篇接下來詳細為大家介紹這
insertinto語句的三種寫法
插入數據是關系數據庫基本的操作之一,它允許用戶將數據插入已經創建的表中。在關系數據庫中,通過使用INSERT INTO語句可以將數據插入到表中的一個或多個列中。 INSERT INTO語句有三種常見
insert into 語句的三種寫法
INSERT INTO是MySQL中常用的一種SQL語句,用于將數據插入到表中。此文將詳細介紹INSERT INTO語句的三種不同寫法及其用途,并提供代碼示例和相關解釋。 正文: 一、基本插入
詳解golang事務的三種寫法
評論