<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Golang transaction 事務使用的正確姿勢

          共 2988字,需瀏覽 6分鐘

           ·

          2022-02-25 19:49

          本文中作者展示了?golang?事務的三種寫法

          第一種寫法

          這種寫法非常樸實,程序流程也非常明確,但是事務處理與程序流程嵌入太深,容易遺漏,造成嚴重的問題

          func?DoSomething()?(err?error)?{
          ????tx,?err?:=?db.Begin()
          ????if?err?!=?nil?{
          ????????return
          ????}


          ????defer?func()?{
          ????????if?p?:=?recover();?p?!=?nil?{
          ????????????tx.Rollback()
          ????????????panic(p)??//?re-throw?panic?after?Rollback
          ????????}
          ????}()


          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????tx.Rollback()
          ????????return
          ????}
          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????tx.Rollback()
          ????????return
          ????}
          ????//?...


          ????err?=?tx.Commit()
          ????return
          }

          第二種寫法

          下面這種寫法把事務處理從程序流程抽離了出來,不容易遺漏,但是作用域是整個函數(shù),程序流程不是很清晰

          func?DoSomething()?(err?error)?{
          ????tx,?err?:=?db.Begin()
          ????if?err?!=?nil?{
          ????????return
          ????}


          ????defer?func()?{
          ????????if?p?:=?recover();?p?!=?nil?{
          ????????????tx.Rollback()
          ????????????panic(p)?//?re-throw?panic?after?Rollback
          ????????}?else?if?err?!=?nil?{
          ????????????tx.Rollback()
          ????????}?else?{
          ????????????err?=?tx.Commit()
          ????????}
          ????}()


          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????return
          ????}
          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????return
          ????}
          ????//?...
          ????return
          }

          第三種寫法

          寫法三是對寫法二的進一步封裝,寫法高級一點,缺點同上

          func?Transact(db?*sql.DB,?txFunc?func(*sql.Tx)?error)?(err?error)?{
          ????tx,?err?:=?db.Begin()
          ????if?err?!=?nil?{
          ????????return
          ????}


          ????defer?func()?{
          ????????if?p?:=?recover();?p?!=?nil?{
          ????????????tx.Rollback()
          ????????????panic(p)?//?re-throw?panic?after?Rollback
          ????????}?else?if?err?!=?nil?{
          ????????????tx.Rollback()
          ????????}?else?{
          ????????????err?=?tx.Commit()
          ????????}
          ????}()


          ????err?=?txFunc(tx)
          ????return?err
          }


          func?DoSomething()?error?{
          ????return?Transact(db,?func?(tx?*sql.Tx)?error?{
          ????????if?_,?err?:=?tx.Exec(...);?err?!=?nil?{
          ????????????return?err
          ????????}
          ????????if?_,?err?:=?tx.Exec(...);?err?!=?nil?{
          ????????????return?err
          ????????}
          ????})
          }

          我的寫法

          經過總結和實驗,我采用了下面這種寫法,defer tx.Rollback() 使得事務回滾始終得到執(zhí)行。當 tx.Commit() 執(zhí)行后,tx.Rollback() 起到關閉事務的作用, 當程序因為某個錯誤中止,tx.Rollback() 起到回滾事務,同事關閉事務的作用。

          普通場景

          func?DoSomething()?(err?error)?{
          ??tx,?_?:=?db.Begin()
          ??defer?tx.Rollback()

          ??if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ??????return
          ??}
          ??if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ??????return
          ??}
          ??//?...


          ??err?=?tx.Commit()
          ??return
          }

          循環(huán)場景

          (1) 小事務 每次循環(huán)提交一次 在循環(huán)內部使用這種寫法的時候,defer 不能使用,所以要把事務部分抽離到獨立的函數(shù)當中

          func?DoSomething()?(err?error)?{
          ????tx,?_?:=?db.Begin()
          ????defer?tx.Rollback()

          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????return
          ????}
          ????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????return
          ????}
          ????//?...


          ????err?=?tx.Commit()
          ????return
          }


          for?{
          ????if?err?:=?DoSomething();?err?!=?nil{
          ?????????//?...
          ????}
          }

          (2) 大事務 批量提交 大事務的場景和普通場景是一樣的,沒有任何區(qū)別

          func?DoSomething()?(err?error)?{
          ????tx,?_?:=?db.Begin()
          ????defer?tx.Rollback()

          ????for{
          ????????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????????return
          ????????}
          ????????if?_,?err?=?tx.Exec(...);?err?!=?nil?{
          ????????????return
          ????????}
          ????????//?...
          ????}

          ????err?=?tx.Commit()
          ????return
          }


          轉自:http://k8i.cn/Ntg8T

          文章轉載:CSDN

          (版權歸原作者所有,侵刪)


          點擊下方“閱讀原文”查看更多

          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼手机高清免费看 | 婷婷综合 | 亚洲区色情区激情区小说纯熟调抖 | 五月丁香免费视频 | www.黄色电影 |