2 回答
TA贡献1862条经验 获得超6个赞
很大程度上取决于您的整个架构是如何设置的。有许多变化和考虑因素需要考虑(我不会详细说明,因为那里有很多文档)。但一般来说,最佳实践是域模型——在许多情况下甚至是服务——完全独立于任何实现选择。它不应该知道 SQL 事务。
例如,如果User是 DDD 术语中的聚合根Picture,Contact并且 和Address是值对象,则User负责一致性。
在我自己的 DDD 代码中,我使用Ports and Adapters架构和CQRS。我可能UpdateUserDetails在应用程序层中有一个命令,它传递了一个存储库实现(例如,对于 SQL 数据库)并进行事务处理。域层将只定义存储库接口。
命令处理程序从存储库中检索聚合根对象User,并对其进行更新(再次以各种方式实现,例如在处理程序本身的单个User.UpdateDetails()或多个步骤中)。只有在没有任何验证或业务规则错误的情况下完成此操作后,处理程序才会持久保存到存储库,在这里我将调用包装到事务中。
不过,我的代码(非常具体)对您没有用处。
相反,请查看出色的Wild Workouts示例,了解 DDD for Go 的完整介绍,包括事务处理。博客系列逐渐重构应用程序,引入更多与 DDD 相关的概念。它从“DDD lite”版本开始(最佳实践:尽可能简单地开始),然后添加 CQRS,甚至进入事件溯源和微服务(由于“最终一致性”,事务的处理方式将完全不同)。
特别是该系列的文章存储库模式:一种简化 Go 服务逻辑的轻松方法,提供了一些关于如何处理事务的有见地的想法。
TA贡献1772条经验 获得超8个赞
而不是声明一个存储库,例如
type UserRepo struct{
db *sql.DB
}
func (s UserRepo)Create(ctx context.Context, u modelUser) error{ ... }
首选签名,例如
type Execer interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}
type Querier interface {
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
}
type UserRepo struct{}
func (s UserRepo)Create(ctx context.Context, db Execer, u modelUser) error{ ... }
它添加了两个接口来抽象 DB 的具体底层类型。
因此,在调用者中,您可以编写类似于
db := GetDB()
tx := db.Begin()
var err error
defer func() {
if err == nil {
err = tx.Commit()
} else {
err = tx.Rollback() // or use a []error, or else, to not shadow the underlying error.
}
}()
var dataUser something
dataUser, err = user.repository.Create(ctx, tx, modelUser)
if err != nil {
return err
}
var dataPic something
dataPic, err = pic.repository.Create(ctx, tx, modelUserPic)
if err != nil {
return err
}
// etc
当您不需要启动事务时,只需传入 db 实例,
db:=GetDB()
dataUser, err := user.repository.Create(ctx, db, modelUser)
if err != nil {return err}
dataPic, err := pic.repository.Create(ctx, db, modelUserPic)
if err != nil {return err}
// etc
考虑到如果您需要可重试的操作,您应该包装负责开始/结束事务的整个代码。
https://golang.org/pkg/database/sql/#Tx
After a call to Commit or Rollback, all operations on the transaction fail with ErrTxDone.
- 2 回答
- 0 关注
- 192 浏览
添加回答
举报
