最近在写 go 项目中发现一个问题,我有一个对外提供的支付接口,接口中又去调了很多封装好的更改数据库的操作函数。然后我发现要是想对整个接口用一个事务的话,需要在接口最开始初始一个*db 连接,然后传给各个函数。这样才能实现一个事务接口。
tx, _ := dao.MysqlDB.Begin() // 初始化 db 连接
defer tx.Rollback()
logic.UpdateProjectDiscountMemo(*tx,proDisMemoList) // 更新项目折扣
logicCreateUserEventsRecord(*tx,groupId) // 更新用户记录
tx.Commit()

dev.to/techschoolguru/a-clean-way-to-implement-database-transaction-in-golang-2ba

光接口最开始初始一个*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 痛不欲生,一吐槽就说是人的问题,和语言无关

一个字,大道至简。

gorm.io/zh_CN/docs/transactions.html
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 上。