在DDD中,聚合根可以拥有存储库。让我们采用订单聚合,它是非持久对应 OrderRepository 和持久对应 OrderUoW 。我们还有 ProductVariant 汇总,用于跟踪订单中产品的库存。它可以有 ProductVariantRepository 和 ProductVariantUoW 。
订单和ProductVariant的工作方式是在订单保留之前,检查库存。如果有库存,则通过调用OrderUoW.Commit()来保持订单。是的,接下来将调用ProductVariantUoW.Commit()来更新产品的库存。
不幸的事情可能会变坏,用户在短时间内购买相同的产品(将其视为两个用户购买相同产品的网络应用程序)。现在,第二个用户的整个事务应该通过恢复刚刚创建的订单而失败。我应该调用OrderUoW来回滚更改(应该从数据库中删除顺序)吗?或者我应该将两个UoW.Commit()操作放在事务范围中,因此一个commit()失败会回滚更改吗?或者两个存储库(Order,ProductVariant)应该只有UoW并且它只需要一个事务范围?
我可以通过说明如何处理涉及多个存储库的事务来简化故事?
答案 0 :(得分:1)
我们可以问的问题是谁在做以下事情:
Order和ProductVariant在订单之前的工作方式是 持续存在,检查库存。如果有库存,那么 订单将被保留通过调用OrderUoW.Commit()。是的 接下来将调用ProductVariantUoW.Commit()来更新库存 的产品。
有些人认为这种工作属于服务层,它允许服务层将聚合对象的事物放入单个事务中。
根据http://www.infoq.com/articles/ddd-in-practice:
有些开发人员更喜欢管理DAO类中的事务 这是一个糟糕的设计。这导致过于细粒度的交易 控件不能提供管理用例的灵活性 事务跨越多个域对象的位置。服务类 应该处理交易;这种方式即使交易跨越 多个域对象,服务类可以管理事务 因为在大多数用例中,Service类处理控件 流动。
我认为,作为使用单个交易的替代方法,您可以使用ProductVariant来声明库存,如果所有必需的库存项目都可用,那么您可以提交订单。否则(即您无法索取订单所需的所有产品),您必须使用补偿交易退回成功申请的库存。结果是,在订单失败的情况下,一些库存将暂时不可用于其他订单,但优点是您可以在没有分布式交易的情况下工作。
尽管如此,这个逻辑仍然属于服务层,而不是DAO类。
答案 1 :(得分:1)
您使用工作单元的方式似乎有点细粒度。万一你没有读过Martin Fowler的作品:http://martinfowler.com/eaaCatalog/unitOfWork.html
据说你想在用例级别处理事务。预先检查库存的事实只是一种便利(UX),并且在持久保存各种位时应检查库存水平。股票不足可能会引发例外。
应设置事务隔离级别,以便连续执行两个“同时”部分。因此,无论谁首先更新库存水平都将“赢”。然后第二个会引发异常。
答案 2 :(得分:1)
如果您可以使用单个UoW,那么这样做,因为它更容易。
如果您的存储库位于不同的数据库(或者可能是一个基于文件而其他数据库不存在),那么您可能会被迫使用多个UoW,但是您也要编写回滚命令,因为如果UoW1保存对SqlRepo OK的更改,但是UoW2无法保存对FileRepo的更改,那么您需要回滚SqlRepo。如果可以避免的话,不要费心去编写所有回滚命令!