-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
我想咨询或探讨一个关于事务问题, 请指教 #2
Comments
还有一个问题: 为何你说"事务逻辑应该作用于用例层(业务逻辑) 不在持久层上", 这样设计有什么好处? 如果非要在Usecase中开启事务, 就不得不让DataService实现EnableTx接口, 我感觉这会导致DataService不干净, 以为我后期可能会使用其他DB(不支持事务的)或者微服务来实现DataService, 这时候就会多出一个EnableTx方法. |
这个设计是可以支持多个DataService场景的。如果增加一个ProductDataInterface,大概的代码如下: import (
github.com/jfeng45/servicetmpl1/applicationservice/dataservice
github.com/jfeng45/servicetmpl1/domain/model
)
// RegistrationTxUseCase implements RegistrationTxUseCaseInterface.
// It has UserDataInterface, which can be used to access persistence layer
type RegistrationTxUseCase struct {
UserDataInterface dataservice.UserDataInterface
ProductDataInterface dataservice.ProductDataInterface
}
// The use case of ModifyAndUnregister with transaction
func (rtuc *RegistrationTxUseCase) ModifyAndUnregisterWithTx(user *model.User, product *model.Product) error {
udi := rtuc.UserDataInterface
pdi := rtuc.ProductDataInterface
return udi.EnableTx(func() error {
// wrap the business function inside the TxEnd function
ModifyAndUnregister(udi, user)
return ReduceProduct(pdi, product)
})
} |
你提到的文章是旧版的,我有一个升级版的文章,比原来的简化了很多。下面是链接。“一个非侵入的Go事务管理库——如何使用” 关于"事务逻辑应该作用于用例层(业务逻辑)不在持久层上",这样做正是为了应对你所描述的情况。因为一个事务经常会跨多个不同的DataService,如果把事务逻辑放在持久层上会很麻烦。而且有的用例需要持久层支持事务,有的不要。这样如果把事务逻辑放在持久层上,持久层就会变得很复杂。现在把事务逻辑放在用例层,持久层就几乎不用考虑事务,变得几乎透明。 至于“可能会使用其他DB(不支持事务的)或者微服务来实现DataService,这时候就会多出一个EnableTx方法.”,这个不是问题。你可以按照你的意愿来实现EnableTx接口。如果是“其他DB(不支持事务的)“,你可以什么也不做或返回错误。微服务也类似。我觉得这正是EnableTx接口的优点,可以处理各种情况。我的QQ是3120156013,不过平时用的不多。 |
对于第一个问题: 我有点不能理解你举例的代码为什么能正确运行. 我试着理解了这个仓库中buildGdbc的代码, 我发现如果如果某Usecase配置了开启事务, 则在这个代码中始终会使用sql.DB.Begin()开启一个新的连接, 这意味着你上面举例的代码中 如果我的理解有误还请更正. 对于第二个问题: 是的, 我也没找到完美的方案, 只能选择相对优雅的方案. |
补充一下, 我忽略了 这个仓库与你发的文章“一个非侵入的Go事务管理库——如何使用”的代码有一点不同: 在仓库中有以下代码: servicetmpl1/app/container/datastorefactory/sqlFactory.go Lines 22 to 28 in ebc0203
而文章中没有, 我应该以哪一个为准? |
我有两个库”/jfeng45/servicetmpl/” 和“/jfeng45/servicetmpl1/”分别对应不同的文章。”/jfeng45/servicetmpl/”对应旧版文章,“/jfeng45/servicetmpl1/”对应新版文章。旧版文章是没有问题的,它不是在容器中获得“*sql.Tx”。新版主要增加了两个功能,“可自我进化”和升级事务。“可自我进化”用的例子是”/jfeng45/order/”和”/jfeng45/payment/”,这两个由于没有使用依赖注入也是没有问题的。但“/jfeng45/servicetmpl1/”确实是有问题的,正如你说,现在的代码如不改动用的不是一个“*sql.Tx”。我这里讲一下大概的修改思路,争取这两天上传代码。 总的来说需要把一个用例的“*sql.Tx”存储在容器中,这样当一个用例有多个DataService时,就能从容器中获得相同的“*sql.Tx”。每个用例会在程序中生成一个唯一的UUID,用它作为主键来存储“*sql.Tx”。 需要在配置文件的”sqlConfigTx“中增加一个新的字段”txNum“来存UUID。当DataService要获取“*sql.Tx”时先检查容器中是否有这个用例的UUID,如果有,就用它。如果没有就创建,并存入容器。当完成用例的实例创建后,从容器中删除UUID。 当代码库的代码和文章中不一致时,以代码库为准。 |
这是一个好的思路! 我好奇对于"容器"的概念 作者是从哪里得到的灵感? |
我拜读你写的文章: 清晰架构(Clean Architecture)的Go微服务: 事物管理, 思路很好, 不过我还有一个问题没思考明白:
不知道你有没有遇到一个事务跨几个DataService的场景?
假如 我定义了两个DataService:
OrderDataInterface
,ProductDataInterface
, 分别处理订单数据与商品数据, 继续, 现在我定义了一个UserCase:OrderUseCase
, 它依赖OrderDataInterface
和ProductDataInterface
来进行下单操作: 新建一个Order并将Product库存减一, 这两个操作我想做到一个事务里.我看到此仓库的代码里只能对其中一个DataService开启事务:
我想让一个事务跨几个DataService, 请问这个情况下我应该如何构建代码?
The text was updated successfully, but these errors were encountered: