DDD设计模式建议交易



众所周知,服务(控制器/用例(层是处理业务逻辑的,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
}
// user_repo.go
func (repo *UserRepo) Save(user models.User) (models.User, error) {
err := repo.DB.Debug().Save(&user).Error
// err handing...
return user, nil
}
// order_repo.go
func (repo *OrderRepo) Save(order models.Order) (models.Order, error) {
err := repo.DB.Debug().Save(&order).Error
// err handing...
return order, nil
}

我希望应用gormdb.Begin()事务变得更加灵活,而不是我当前的代码太静态。那么我应该去掉这个戈姆吗。DB回购,但

i。在戈姆路过。数据库通过参数??

tx := s.DB.Begin()
createdUser, err := s.UserRepo.Save(user, tx)

ii。还是直接在服务层运行查询??(但它打破了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()

根据DDD,交易不应跨越聚合边界

参考文献:

  • https://martinfowler.com/bliki/DDD_Aggregate.html
  • 定义聚合边界

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

在为聚合编写存储库时,您可以巧妙地将事务隐藏在存储库层中

我通常遵循以下界面

// 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
}

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

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

相关内容

  • 没有找到相关文章

最新更新