您现在的位置是:亿华云 > 应用开发
Golang transaction 事务使用的正确姿势
亿华云2025-10-04 00:52:41【应用开发】0人已围观
简介本文中作者展示了golang事务的三种写法。第一种写法这种写法非常朴实,程序流程也非常明确,但是事务处理与程序流程嵌入太深,容易遗漏,造成严重的问题funcDoSomething()(errerror
本文中作者展示了 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
}
第二种写法
下面这种写法把事务处理从程序流程抽离了出来,不容易遗漏,正确姿势但是正确姿势作用域是整个函数,亿华云计算程序流程不是正确姿势很清晰
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() 使得事务回滚始终得到执行。正确姿势当 tx.Commit() 执行后,正确姿势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
}
循环场景
(1) 小事务 每次循环提交一次 在循环内部使用这种写法的时候,defer 不能使用,所以要把事务部分抽离到独立的函数当中
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) 大事务 批量提交 大事务的场景和普通场景是一样的,站群服务器没有任何区别
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
}
很赞哦!(18226)
站长推荐
其次,一般域名注册有一个获取密码的按钮,域名注册商点击后会向您发送密码。在得到域名注册商发送的密码后,将其传输到域名服务提供商网站,然后输入密码,此时域名呈现申请状态。提交申请后,原注册人通常会向您发送一封电子邮件,询问您是否同意转让。此时,您只需点击同意转移按钮,域名注册商就可以成功转移。
Python协程知多少
Harmonyos网络通信真机Demo演练(一)之TCP聊天室
《亲爱的》原型家庭团聚!借助人像比对和DNA信息库,技术带来“团圆”
2、根据用户基础选择访问提供程序。由于互联问题的存在,接入商的选择也非常重要,如果用户群主要在联通,尽量选择联通接入较好的接入商,如果用户群主要在电信,那么选择电信接入较好的接入商。如果用户组位于国家/地区,则选择更好的访问提供程序进行交互。
开发环境下,如何通过一个命令让 Fastapi 和 Celery 一起工作
如果需要保护多个域名怎么办?
量子计算之父获艾萨克·牛顿奖!提出世界第一个量子计算机构想