Golang Go语言中各位大佬都是怎么使用事务?有没有更好的方式

最近在写 go 项目中发现一个问题,我有一个对外提供的支付接口,接口中又去调了很多封装好的更改数据库的操作函数。然后我发现要是想对整个接口用一个事务的话,需要在接口最开始初始一个*db 连接,然后传给各个函数。这样才能实现一个事务接口。

tx, _ := dao.MysqlDB.Begin()  // 初始化 db 连接
defer tx.Rollback()
logic.UpdateProjectDiscountMemo(*tx,proDisMemoList)  // 更新项目折扣
logicCreateUserEventsRecord(*tx,groupId)       // 更新用户记录
tx.Commit()

Golang Go语言中各位大佬都是怎么使用事务?有没有更好的方式

更多关于Golang Go语言中各位大佬都是怎么使用事务?有没有更好的方式的实战教程也可以访问 https://www.itying.com/category-94-b0.html

42 回复

更多关于Golang Go语言中各位大佬都是怎么使用事务?有没有更好的方式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


光接口最开始初始一个*db 连接还不一定行
比如你各个函数里面又进行了 begin 和 commit ,形成事务嵌套,这还要看你事务管理器有没有实现,没实现的话还得自己再包一层逻辑。

放在中间件里 commit 吧

可以考虑把 db 放到 context 里面,context 一直向下传递,logic 层获取 db 只需要从 context 获取就好。
如果上层的 logic 想开启事务,就把 db=db.Begin()放到 context 里面,这下下层的 logic 获取到的就是开启事务的 db 了,然后上层根据返回的 error 进行 commit 或者 rollback

封装一个 session 或者叫 context ,receriver 中实现各种数据库逻辑,最后返回自身实现链式调用。

db.Transaction(func(tx *gorm.DB) error {
orderHelp := orderhelp{tx: tx}
orderHelp 实现业务逻辑
exampleHelp := examplehelp{tx:tx}
})

go 用事务这么麻烦吗, 没现成框架吗…

#7 大道至简

惊讶,同 7 楼所问。。。

把事务塞进 context 传下去,反正 context 是 go 标准功能了,下面的方法要事务的话就从 context 里拿

go 就是这样的没办法

自己包一下

#7
#9

java 转过来的 ,写了一段时间 crud 痛不欲生,一吐槽就说是人的问题,和语言无关

一个字,大道至简。





https://gorm.io/zh_CN/docs/transactions.html
https://entgo.io/zh/docs/transactions/

想怎么写怎么写,还特意帮你们点好了中文,慢慢享用。

还有 Go 本身就是一种拆开写的语言,用惯了语法糖的确实容易不习惯,关键能否接受这种思想吧。

手动控制事务,好原始

看到 14 楼贴的方案,能体会到你说的痛不欲生。。。。

#16

只能说大道至简,另外吐槽下,go 木有 set ,github 有一百多个 set 实现

我是这么写的
type Store struct {
db *gorm.DB
tx *gorm.DB
}

func (s *Store) Begin() {

}

没编辑完就回复了。。
func (s *Store) Begin() {
s.tx = s.db.Begin()
}
// Commit 或 Rollback
func (s *Store) Commit() {
s. tx.Commit()
s.tx = s.db
}

Go 语言要求你处理每个阶段产生的错误,所以不存在异常。对于大的团队项目来说只要你不瞎搞一般开发者也能写出比较高质量的代码。看你对自身的要求了。

你看,我还没说 if err 的问题你自己就先忙着解释了。。。。我这说的是手动控制事务的事呢

都是自己套的. Database 封装一层,

一般是
func BeginReadWrite(ctx context.Context, f func(ctx context.Context) error) error
去调用 f 的时候, ctx 里会带上 transaction 对象, 然后在这里处理错误, 和 defer 里面抓错误, 来 commit 或 rollback

然后 Repository 层被调用的时候, 从 context 里取出来.

transaction 一般最好是 interface, 这样方便有时候不需要事务, 传入裸的连接直接用, 也不用改里面的代码.

又来一个小丑。国内现状的代表

这就飙脏字了?这素质能代表 go 开发者集体么?不能就咽回去(^_^)

#14 gorm 那种写法,如果逻辑都在一起还好说,但是对应楼主说那种,调用链比较长,每个环节都可能有事务就麻烦了,需要共用一个初始的事务实例,类似 Context 那种一路传下去还挺难受的。

#7 mongo 官方的驱动比 mysql 的好用太多了。一个天一个地

首先事务的范围还是尽量控制在小范围,非要长调用链,可以试试上面 gorm 里的其他写法。

gorm 怎么说呢,不一定全部盲目采信它的模式。它也是 v2 才支持传递 context 的,v1 的时候做链路追踪都只能挂到 Scope 上。

#24

看到了吗,国内 go 圈子的现状,不接受质疑。质疑的话你就是「🤡」

关键大多数都是 crud boy ,对于我这种渣渣,go 确实生产力不够强大。

拿着步枪当宝贝。你看他那样,上来就先给自己裹小脚“控制范围”,这用得着他说嘛,没有就是没有,原始就是原始,麻烦就是麻烦,跟控制范围有鸡毛关系。还什么 if err 能产出较高质量代码,头一回见这么能扯的。

啥是宗教?这玩意就是典型的宗教信徒。

忘了圈你,在楼上。

大道至简 好牛逼

所以为啥 java 转 go ,图个啥呢?

#34

换组了,就换技术栈了

我也是从 Java 转到 go 的,我发现接手的项目竟然没有事务控制!每一步更新表都能从表里读出来。。。。

#36

这个就是设计的问题了,和语言无关哈哈,这里讨论的是 go 主流的 orm 事务太难用了哈哈

在深圳,求一枚 Golang 大佬!!欢迎砸简历 V:Ifboredgunquxuexi.

确实是与语言无关,只是现成已有的 orm 没有封装好;当然,最大问题还是 go 相对来说比较新的语言,成熟的轮子少,而且主要场景是基础设施

毕竟传统的企业应用,Java 都有现成的;没必要为了用新 语言就全部重写
而且现在微服务(包括服务网格这类的),都支持 sidecar ;所以一个系统多语言架构也越来越多常见

坐标深圳,求一枚 Golang 大佬!!欢迎砸简历 V:Ifboredgunquxuexi.

不错的文章

在Go语言中处理事务时,通常我们会使用数据库驱动(如database/sql包)结合具体数据库的支持来实现。事务管理关键在于确保一组操作要么全部成功,要么全部失败,以保持数据的一致性和完整性。

以下是一个使用MySQL数据库和Go语言管理事务的基本示例:

  1. 开启事务:通过db.Begin()方法开启一个新的事务。
  2. 执行SQL操作:在事务上下文中执行SQL语句。
  3. 提交或回滚:根据操作结果调用tx.Commit()tx.Rollback()
tx, err := db.Begin()
if err != nil {
    // 处理错误
    return
}

// 执行SQL操作
_, err = tx.Exec("INSERT INTO table_name (column) VALUES (?)", value)
if err != nil {
    tx.Rollback() // 回滚事务
    // 处理错误
    return
}

// 提交事务
err = tx.Commit()
if err != nil {
    // 处理提交错误
    return
}

对于更好的实践方式,可以考虑以下几点:

  • 使用上下文(context.Context):在长时间运行的事务中管理超时和取消信号。
  • 封装事务逻辑:将事务逻辑封装到函数中,简化代码结构,提高复用性和可读性。
  • 错误处理:确保每个SQL操作都进行了错误检查,并在必要时进行回滚。
  • 日志记录:记录事务的开始、提交和回滚,以便于调试和审计。

这些实践可以帮助你更有效地管理Go语言中的数据库事务。

回到顶部