最近在写 go 项目中发现一个问题,我有一个对外提供的支付接口,接口中又去调了很多封装好的更改数据库的操作函数。然后我发现要是想对整个接口用一个事务的话,需要在接口最开始初始一个*db 连接,然后传给各个函数。这样才能实现一个事务接口。
tx, _ := dao.MysqlDB.Begin() // 初始化 db 连接
defer tx.Rollback()
logic.UpdateProjectDiscountMemo(*tx,proDisMemoList) // 更新项目折扣
logicCreateUserEventsRecord(*tx,groupId) // 更新用户记录
tx.Commit()
1
janxin 2022-02-25 11:16:37 +08:00
|
2
cheng6563 2022-02-25 11:20:10 +08:00
光接口最开始初始一个*db 连接还不一定行
比如你各个函数里面又进行了 begin 和 commit ,形成事务嵌套,这还要看你事务管理器有没有实现,没实现的话还得自己再包一层逻辑。 |
3
imherer 2022-02-25 11:24:46 +08:00
放在中间件里 commit 吧
|
4
godlovesxcjtest 2022-02-25 12:50:41 +08:00 1
可以考虑把 db 放到 context 里面,context 一直向下传递,logic 层获取 db 只需要从 context 获取就好。
如果上层的 logic 想开启事务,就把 db=db.Begin()放到 context 里面,这下下层的 logic 获取到的就是开启事务的 db 了,然后上层根据返回的 error 进行 commit 或者 rollback |
5
qieqie 2022-02-25 12:56:40 +08:00
封装一个 session 或者叫 context ,receriver 中实现各种数据库逻辑,最后返回自身实现链式调用。
|
6
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} }) |
7
nekoneko 2022-02-25 15:40:44 +08:00
go 用事务这么麻烦吗, 没现成框架吗....
|
9
9c04C5dO01Sw5DNL 2022-02-25 15:54:23 +08:00
惊讶,同 7 楼所问。。。
|
10
BeautifulSoap 2022-02-25 16:17:22 +08:00 via Android
把事务塞进 context 传下去,反正 context 是 go 标准功能了,下面的方法要事务的话就从 context 里拿
go 就是这样的没办法 |
11
tiedan 2022-02-25 16:46:58 +08:00
自己包一下
|
12
28Sv0ngQfIE7Yloe 2022-02-25 16:56:51 +08:00
|
13
Qseven 2022-02-25 17:00:46 +08:00
一个字,大道至简。
|
14
Hanggi 2022-02-25 17:01:59 +08:00 1
@longmeier90
@nekoneko @giiiiiithub @Morii https://gorm.io/zh_CN/docs/transactions.html https://entgo.io/zh/docs/transactions/ 想怎么写怎么写,还特意帮你们点好了中文,慢慢享用。 还有 Go 本身就是一种拆开写的语言,用惯了语法糖的确实容易不习惯,关键能否接受这种思想吧。 |
15
9c04C5dO01Sw5DNL 2022-02-25 17:22:01 +08:00
@Hanggi 手动控制事务,好原始
|
16
9c04C5dO01Sw5DNL 2022-02-25 17:22:45 +08:00
@Morii 看到 14 楼贴的方案,能体会到你说的痛不欲生。。。。
|
17
28Sv0ngQfIE7Yloe 2022-02-25 17:40:54 +08:00
|
18
evan0724 2022-02-25 17:44:44 +08:00 1
我是这么写的
type Store struct { db *gorm.DB tx *gorm.DB } func (s *Store) Begin() { } |
19
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 } |
20
Hanggi 2022-02-25 18:16:23 +08:00 via Android
@giiiiiithub Go 语言要求你处理每个阶段产生的错误,所以不存在异常。对于大的团队项目来说只要你不瞎搞一般开发者也能写出比较高质量的代码。看你对自身的要求了。
|
21
9c04C5dO01Sw5DNL 2022-02-25 18:34:10 +08:00
@Hanggi 你看,我还没说 if err 的问题你自己就先忙着解释了。。。。我这说的是手动控制事务的事呢
|
22
joesonw 2022-02-25 18:46:31 +08:00
都是自己套的. Database 封装一层,
一般是 func BeginReadWrite(ctx context.Context, f func(ctx context.Context) error) error 去调用 f 的时候, ctx 里会带上 transaction 对象, 然后在这里处理错误, 和 defer 里面抓错误, 来 commit 或 rollback 然后 Repository 层被调用的时候, 从 context 里取出来. transaction 一般最好是 interface, 这样方便有时候不需要事务, 传入裸的连接直接用, 也不用改里面的代码. |
23
Hanggi 2022-02-25 18:54:53 +08:00 via Android 1
@giiiiiithub 又来一个小丑。国内现状的代表
|
24
9c04C5dO01Sw5DNL 2022-02-25 18:56:59 +08:00 4
@Hanggi 这就飙脏字了?这素质能代表 go 开发者集体么?不能就咽回去(*^_^*)
|
25
FrankAdler 2022-02-25 19:18:42 +08:00
@Hanggi #14 gorm 那种写法,如果逻辑都在一起还好说,但是对应楼主说那种,调用链比较长,每个环节都可能有事务就麻烦了,需要共用一个初始的事务实例,类似 Context 那种一路传下去还挺难受的。
|
27
Hanggi 2022-02-25 20:54:12 +08:00 via iPhone
@FrankAdler 首先事务的范围还是尽量控制在小范围,非要长调用链,可以试试上面 gorm 里的其他写法。
|
28
joesonw 2022-02-26 14:54:18 +08:00 via iPhone
gorm 怎么说呢,不一定全部盲目采信它的模式。它也是 v2 才支持传递 context 的,v1 的时候做链路追踪都只能挂到 Scope 上。
|
29
28Sv0ngQfIE7Yloe 2022-02-28 10:13:14 +08:00
|
30
9c04C5dO01Sw5DNL 2022-02-28 11:17:59 +08:00
拿着步枪当宝贝。你看他那样,上来就先给自己裹小脚“控制范围”,这用得着他说嘛,没有就是没有,原始就是原始,麻烦就是麻烦,跟控制范围有鸡毛关系。还什么 if err 能产出较高质量代码,头一回见这么能扯的。
啥是宗教?这玩意就是典型的宗教信徒。 |
31
9c04C5dO01Sw5DNL 2022-02-28 11:18:58 +08:00
@Morii 忘了圈你,在楼上。
|
32
zzy11 2022-02-28 17:00:16 +08:00 1
1. 使用 context 存储 tx,参考 https://github.com/win5do/go-microservice-demo/blob/main/docs/sections/gorm.md
2. new 一个新的 repo,参考 https://lailin.xyz/post/clean-arch-transaction.html |
33
dany813 2022-02-28 17:31:06 +08:00
大道至简 好牛逼
|
35
28Sv0ngQfIE7Yloe 2022-03-01 13:39:25 +08:00
|
36
lessMonologue 2022-03-01 14:47:58 +08:00
@Morii 我也是从 Java 转到 go 的,我发现接手的项目竟然没有事务控制!每一步更新表都能从表里读出来。。。。
|
37
28Sv0ngQfIE7Yloe 2022-03-01 15:57:36 +08:00
|
38
aurtech 2022-03-10 17:52:15 +08:00
在深圳,求一枚 Golang 大佬!!欢迎砸简历 V:Ifboredgunquxuexi.
|
39
xsen 2022-03-10 20:33:21 +08:00
确实是与语言无关,只是现成已有的 orm 没有封装好;当然,最大问题还是 go 相对来说比较新的语言,成熟的轮子少,而且主要场景是基础设施
毕竟传统的企业应用,Java 都有现成的;没必要为了用新 语言就全部重写 而且现在微服务(包括服务网格这类的),都支持 sidecar ;所以一个系统多语言架构也越来越多常见 |
40
aurtech 2022-03-11 15:23:11 +08:00
坐标深圳,求一枚 Golang 大佬!!欢迎砸简历 V:Ifboredgunquxuexi.
|