各位大佬在 go 中都是怎么使用事务?有没有更好的方式

2022-02-25 11:07:06 +08:00
 longmeier90

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

tx, _ := dao.MysqlDB.Begin()  // 初始化 db 连接
defer tx.Rollback()
logic.UpdateProjectDiscountMemo(*tx,proDisMemoList)  // 更新项目折扣
logicCreateUserEventsRecord(*tx,groupId)       // 更新用户记录
tx.Commit()
7116 次点击
所在节点    Go 编程语言
41 条回复
janxin
2022-02-25 11:16:37 +08:00
cheng6563
2022-02-25 11:20:10 +08:00
光接口最开始初始一个*db 连接还不一定行
比如你各个函数里面又进行了 begin 和 commit ,形成事务嵌套,这还要看你事务管理器有没有实现,没实现的话还得自己再包一层逻辑。
imherer
2022-02-25 11:24:46 +08:00
放在中间件里 commit 吧
godlovesxcjtest
2022-02-25 12:50:41 +08:00
可以考虑把 db 放到 context 里面,context 一直向下传递,logic 层获取 db 只需要从 context 获取就好。
如果上层的 logic 想开启事务,就把 db=db.Begin()放到 context 里面,这下下层的 logic 获取到的就是开启事务的 db 了,然后上层根据返回的 error 进行 commit 或者 rollback
qieqie
2022-02-25 12:56:40 +08:00
封装一个 session 或者叫 context ,receriver 中实现各种数据库逻辑,最后返回自身实现链式调用。
labulaka521
2022-02-25 13:25:20 +08:00
db.Transaction(func(tx *gorm.DB) error {
orderHelp := orderhelp{tx: tx}
orderHelp 实现业务逻辑
exampleHelp := examplehelp{tx:tx}
})
nekoneko
2022-02-25 15:40:44 +08:00
go 用事务这么麻烦吗, 没现成框架吗....
zoharSoul
2022-02-25 15:48:11 +08:00
@nekoneko #7 大道至简
9c04C5dO01Sw5DNL
2022-02-25 15:54:23 +08:00
惊讶,同 7 楼所问。。。
BeautifulSoap
2022-02-25 16:17:22 +08:00
把事务塞进 context 传下去,反正 context 是 go 标准功能了,下面的方法要事务的话就从 context 里拿

go 就是这样的没办法
tiedan
2022-02-25 16:46:58 +08:00
自己包一下
28Sv0ngQfIE7Yloe
2022-02-25 16:56:51 +08:00
@nekoneko #7
@giiiiiithub #9

java 转过来的 ,写了一段时间 crud 痛不欲生,一吐槽就说是人的问题,和语言无关
Qseven
2022-02-25 17:00:46 +08:00
一个字,大道至简。
Hanggi
2022-02-25 17:01:59 +08:00
@longmeier90
@nekoneko
@giiiiiithub
@Morii
https://gorm.io/zh_CN/docs/transactions.html
https://entgo.io/zh/docs/transactions/

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

还有 Go 本身就是一种拆开写的语言,用惯了语法糖的确实容易不习惯,关键能否接受这种思想吧。
9c04C5dO01Sw5DNL
2022-02-25 17:22:01 +08:00
@Hanggi 手动控制事务,好原始
9c04C5dO01Sw5DNL
2022-02-25 17:22:45 +08:00
@Morii 看到 14 楼贴的方案,能体会到你说的痛不欲生。。。。
28Sv0ngQfIE7Yloe
2022-02-25 17:40:54 +08:00
@giiiiiithub #16

只能说大道至简,另外吐槽下,go 木有 set ,github 有一百多个 set 实现
evan0724
2022-02-25 17:44:44 +08:00
我是这么写的
type Store struct {
db *gorm.DB
tx *gorm.DB
}

func (s *Store) Begin() {

}
evan0724
2022-02-25 17:48:08 +08:00
没编辑完就回复了。。
func (s *Store) Begin() {
s.tx = s.db.Begin()
}
// Commit 或 Rollback
func (s *Store) Commit() {
s. tx.Commit()
s.tx = s.db
}
Hanggi
2022-02-25 18:16:23 +08:00
@giiiiiithub Go 语言要求你处理每个阶段产生的错误,所以不存在异常。对于大的团队项目来说只要你不瞎搞一般开发者也能写出比较高质量的代码。看你对自身的要求了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/836337

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX