【问题标题】:Transaction in DDD design pattern adviceDDD 设计模式建议中的事务
【发布时间】:2021-04-10 21:51:37
【问题描述】:

我们知道服务(控制器/用例)层是处理业务逻辑, repo 是用来处理 db 查询的

现在我有:

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
}

我希望应用 gorm db.Begin() 事务变得更加灵活,而不是我当前的代码过于静态。 所以我应该删除gorm.DB repo 但是

我。通过params传入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()

【问题讨论】:

    标签: database go transactions domain-driven-design go-gorm


    【解决方案1】:

    根据 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
    }
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-03
        • 1970-01-01
        • 1970-01-01
        • 2013-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多