本文中作者展示了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文章
9332浏览量
149047 -
程序
+关注
关注
117文章
3848浏览量
85472 -
函数
+关注
关注
3文章
4422浏览量
67851
原文标题: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
•1355次阅读
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事务的三种写法
评论