Database DDD设计模式建议中的事务

Database DDD设计模式建议中的事务,database,go,transactions,domain-driven-design,go-gorm,Database,Go,Transactions,Domain Driven Design,Go Gorm,正如我们所知,服务控制器/用例层负责处理业务逻辑, repo是用来处理数据库查询的 现在我有: func (s *OrderService) Create(order models.Order) (models.Order, error) { ... user := models.User{ Contact: order.Address.Contact, } createdUser, err := s.UserRepo.Save(user) // err han

正如我们所知,服务控制器/用例层负责处理业务逻辑, repo是用来处理数据库查询的

现在我有:

func (s *OrderService) Create(order models.Order) (models.Order, error) {
  ...
  user := models.User{
    Contact: order.Address.Contact,
  }
  createdUser, err := s.UserRepo.Save(user)   
  // err handling...

  order.User = user
  createdOrder, err := s.OrderRepo.save(order)
  // err handling...

  return order, nil
}
我希望应用gorm db。Begin transaction变得更加灵活,而不是我当前的代码过于静态。 那么我应该删除gorm.DB回购协议吗

一,。通过参数传入gorm.DB

tx := s.DB.Begin()
createdUser, err := s.UserRepo.Save(user, tx)
二,。或者直接在服务层运行查询??但它打破了ddd的设计理念

tx := s.DB.Begin()
createdUser, err := tx.Create(&user)
if err != nil {
  tx.Rollback()
}
createdOrder, err := tx.Create(&order)  
if err != nil {
  tx.Rollback()
}
tx.Commit()

GORM调用绝对应该在存储层中保持抽象。若将事务句柄等实现细节泄露给业务逻辑,存储层将与特定的存储实现紧密耦合

在域驱动的世界中,人们可能应该以这样的方式对存储层的接口进行建模,即它具有使用域对象操作业务逻辑所需的所有操作,而不是数据库提供的基本操作。关键是,如果以后从SQL数据库切换到S3 REST API,则面向业务逻辑的接口将保持不变。因此,取而代之或在orderepo.Save之上,我还将创建orderepo.SaveAsNewUser Order,User,err,这将在内部利用数据库事务。

根据DDD,事务不应跨越聚合边界

参考资料:

如果我们出于某种原因需要在事务中更新它们,您可能需要重新查看它们是否应该是某个聚合的一部分

在编写用于聚合的存储库时,可以将事务整齐地隐藏在存储库层中

我通常遵循以下界面

// holds the business logic to modify the aggregate, provided by business layer
type AggregateUpdateFunction func (a *Aggregate) error
    
type Repository interface {
      Create(ctx context.Context, aggregate *Aggregate)
      Read(ctx context.Context, id string) *Aggregate
      // starts a read-modify-write cycle internally in a transaction   
      Update(ctx context.Context, id string, updateFunc AggregateUpdateFunction) error
}
// holds the business logic to modify the aggregate, provided by business layer
type AggregateUpdateFunction func (a *Aggregate) error
    
type Repository interface {
      Create(ctx context.Context, aggregate *Aggregate)
      Read(ctx context.Context, id string) *Aggregate
      // starts a read-modify-write cycle internally in a transaction   
      Update(ctx context.Context, id string, updateFunc AggregateUpdateFunction) error
}