Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Architecture 在DDD环境下应如何处理交易_Architecture_Transactions_Domain Driven Design_Software Design_Unit Of Work - Fatal编程技术网

Architecture 在DDD环境下应如何处理交易

Architecture 在DDD环境下应如何处理交易,architecture,transactions,domain-driven-design,software-design,unit-of-work,Architecture,Transactions,Domain Driven Design,Software Design,Unit Of Work,在DDD上下文中,当您处理域事件时,事务应该从何处开始和结束 基础设施层具有UoW实现 /// => configured via DI as Per Request class UnitOfWork : IUnitOfWork { ITransaction _transaction; static ISessionFactory _factory; ISession _session UnitOfWork() { _

在DDD上下文中,当您处理域事件时,事务应该从何处开始和结束

基础设施层具有UoW实现

/// => configured via DI as Per Request
class UnitOfWork : IUnitOfWork
{
     ITransaction _transaction;
     static ISessionFactory _factory; 
     ISession _session

     UnitOfWork()
     {
         _session = _factory.OpenSession();
         _transaction = _session.BeginTransaction();  ///=> start transaction 
     }

     void Commit()
     {
          try
             _transaction.Commit();
          catch
            _transaction.Rollback(); 
          finally
            Dispose();
     } 
}
应用层用例处理程序

class SomeAppServiceUseCaseHandler : IUseCaseHandler
{
      IUnitOfWork _uow;
      ISomeRepo _repo;

      AppService(IUnitOfWork uow, ISomeRepo repo)
      {
          _uow = uow;
          _repo = repo;
      }

      void UseCaseHandler(Request request)
      {

         SomeAggregate agg = _repo.GetAggregate(request.Id) 

                       agg.DoSomethingToChangeState();

         _repo.UpdateAgg(agg);

         _uow.Commit(agg);  ///=> commit changes for this transaction success
      }
}
在Domain.Layer中,该方法还将向聚合的域事件列表添加Domain.Event

SomeAggregate : AggregateRoot
{
   DoSomethingToChangeState()
   {
       .... do something

       var someObject;
       base.AddEvent(new SomethingHappenedEvent(someObject)));
   }
}
Application.Layer具有Domain.Event处理程序

class SomethingHappenedEventHander : Handler<SomethingHappenedEvent>
{
    IRepo repo;
    IUnitOfWork _uow;

    DomainEventHander(IRepo repo, IUnitOfWork uow)
    {
        _repo = repo;
        _uow= uow;
    }

    HandleEvent(someObject)
    {
         AnotherAggregate agg = new AnotherAggregate ();
                          agg.DoSomeCommand(someObject);

         _repo.Create(agg);
         _uow.Commit();  ///=> commit changes for same transaction fail, should rollback prev transaction as well
    }
}
class SomethingHappendEventHander:Handler
{
IRepo回购;
工作单元;
DomainEventHander(IRepo回购协议,IUnitOfWork uow)
{
_回购=回购;
_uow=uow;
}
HandleEvent(someObject)
{
AnotherAggregate agg=新的AnotherAggregate();
agg.DoSomeCommand(someObject);
_回购创建(agg);
_提交();//=>提交同一事务的更改失败,也应回滚上一个事务
}
}
我觉得这不对

  • 谁应该发布该事件?据我所见,UoW应该在Commit()方法中这样做,但我认为这是不对的,我认为UoW不应该这样做,但我看不出还有谁可以这样做

  • 如果在链中的某个点出现故障,我已经提交了一些数据,如果某个过程中出现故障,我很可能不想这样做


  • 那么,如何正确处理这两种情况呢

    如Constantin所述,每个命令只能更新一个聚合。为什么?因为通过更新一个事务中的多个聚合,会降低系统的吞吐量。数据库事务边界越大,在写入数据时越有可能面临争用,因此希望尽可能保持事务的细粒度

    关于你的问题:

  • UnitOfWork当然可以保存更改。或者,您的Repo类也可以使用新方法IRepo.Save(聚合)执行相同的操作:

  • 你的担心是正确的。您可以(也可能应该)将UnitOfWork移出处理程序/UseCaseHandler级别的范围,这样您就不会在每个处理程序中都有提交UoW的样板代码。然后,您可以在一个数据库事务中保存这两个聚合。更好的方法是采用一种允许您从故障中恢复的体系结构。你可以:

  • 处理命令并在事件存储中生成事件。(UoW将执行此操作)
  • 轮询事件存储中的新事件并将其发布到队列
  • 从队列中读取事件并将其分派给任何已注册的处理程序
  • 在事件存储中保存新事件(同样使用UoW),该过程将重复 如果上述任何一个步骤失败,处理将从该点开始,并确保工作完成。通过这种方法,您的应用程序更具弹性,事务边界也得到了正确应用


  • DDD声明每个事务只应修改一个聚合。是的,这是真的,但如何处理多个聚合更新?我认为我不应该在Saga/processmanager中的Application.Layer usecasehandler中开始事务。如果需要回滚聚合,则边界有问题,或者需要将其建模为业务流程
    _repo.Save(agg);