5

在 DDD 中,聚合根可以有一个存储库。让我们采用一个Order聚合,它是非持久性对应物OrderRepository和持久性对应物OrderUoW。我们还有ProductVariant聚合,它跟踪订单中产品的库存。它可以有ProductVariantRepositoryProductVariantUoW

Order 和 ProductVariant 的工作方式是在保留订单之前检查库存。如果有库存,订单将通过调用 OrderUoW.Commit() 进行持久化。是的,接下来会调用 ProductVariantUoW.Commit() 来更新产品的库存。

不幸的是,事情可能会变糟,用户在短时间内购买了相同的产品(将其视为两个用户购买相同产品的网络应用程序)。现在,第二个用户的整个交易应该会因为恢复刚刚创建的订单而失败。我应该调用 OrderUoW 来回滚更改(应该从数据库中删除订单)吗?或者我应该把两个 UoW.Commit() 操作都放在一个事务范围内,所以一个 commit() 失败会回滚更改?或者两个存储库(Order、ProductVariant)都应该只有 UoW 并且只需要一个事务范围?

我可以通过说,在涉及多个存储库的情况下如何处理事务?

4

3 回答 3

1

您使用工作单元的方式似乎有点细粒度。以防万一您还没有阅读 Martin Fowler 的观点:http ://martinfowler.com/eaaCatalog/unitOfWork.html

话虽如此,您希望在用例级别处理事务。预先检查库存的事实只是一种方便(UX),并且在持久化各种位时也应该检查库存水平。库存不足可以引发异常。

应设置事务隔离级别,以便两个“同时”部分连续执行。因此,无论谁先更新库存水平,都会“获胜”。然后第二个将引发异常。

于 2013-01-05T05:45:20.673 回答
1

如果您可以使用单个 UoW,那么就这样做,因为它更容易。

如果您的存储库位于不同的数据库上(或者一个是基于文件的,而其他的不是),那么您可能会被迫使用多个 UoW,但是您也在编写回滚命令,因为如果 UoW1 将更改保存到 SqlRepo好的,但是 UoW2 无法保存对 FileRepo 的更改,那么您需要回滚 SqlRepo。如果可以避免的话,不要费心编写所有回滚命令的东西!

于 2015-04-10T10:15:06.580 回答
1

我们可以问的一个问题是谁在做以下事情:

Order 和 ProductVariant 的工作方式是在保留订单之前检查库存。如果有库存,订单将通过调用 OrderUoW.Commit() 进行持久化。是的,接下来会调用 ProductVariantUoW.Commit() 来更新产品的库存。

有人认为这种工作属于服务层,它允许服务层将跨聚合对象的事物放入单个事务中。

根据http://www.infoq.com/articles/ddd-in-practice

一些开发人员更喜欢在 DAO 类中管理事务,这是一个糟糕的设计。这导致太细粒度的事务控制,无法灵活管理事务跨越多个域对象的用例。服务类应该处理事务;这样,即使事务跨越多个域对象,服务类也可以管理事务,因为在大多数用例中,服务类处理控制流。

我认为作为使用单个事务的替代方法,您可以使用 ProductVariant 声明库存,并且,如果所有必要的库存项目都可用,那么您可以提交订单。否则(即,您无法领取订单所需的所有产品)您必须退回使用补偿交易成功领取的库存。结果是,在一个订单提交不成功的情况下,一些库存会暂时出现其他订单不可用,但好处是你可以在没有分布式事务的情况下工作。

尽管如此,这个逻辑仍然属于服务层,而不是 DAO 类。

于 2013-01-05T01:06:08.200 回答