我正在阅读 Vernon 的文章Effective Aggregate Design。我有一个问题,为什么每个事务只修改一个聚合实例?
让我们举个例子,考虑一个仓库库存管理的故事。
库存表示仓库中具有数量的项目。5以上海仓库实施领域驱动设计书籍为例。
条目表示有关Inventory上的输入/输出操作的日志。以上海仓库为例,进入2本实现领域驱动设计的书籍。
如果提交条目,则需要更改Inventory的数量。
我很容易想到,这是一个不变量,可以通过事务一致性来实现。
解决方案 A:使用一个 Aggregate 和 cluster Entry进入Inventory。
public class Inventory implements Aggregate<Inventory> {
private InventoryIdentity id;
private Sku sku;
private int quantity;
private List<Entry> entries;
public void add(Entry entry) {
this.quantity += entry.getQuantity();
this.entries.add(entry);
}
}
public class Entry implements LocalEntity<Entry> {
private int quantity;
// some other attributes such as whenSubmitted
}
public class TransactionalInventoryAdminService impelments InventoryAdminService, ApplicationService {
@Override
@Transactional
public void handle(InventoryIdentity inventoryId, int entryQuantity, ...other entry attributes)
Inventory inventory = inventoryRepository.findBy(inventoryId);
Entry entry = inventory.newEntry(entryQuantity, ..);
inventory.add(entry);
inventoryRepository.store(inventory);
}
}
解决方案 B :对库存和分录使用单独的聚合。
public class Inventory implements Aggregate<Inventory> {
private InventoryIdentity id;
private Sku sku;
private int quantity;
public void add(int quantity) {
this.quantity += quantity;
}
}
public class Entry implements LocalEntity<Entry> {
private Inventory inventory;
private int quantity;
private boolean handled = false;
// some other attributes such as whenSubmitted
public void handle() {
if (handled) {
throw .....
} else {
this.inverntory.add(quantity);
this.handled = true;
}
}
}
public class TransactionalInventoryAdminService impelments InventoryAdminService, ApplicationService {
@Override
@Transactional
public void handle(InventoryIdentity inventoryId, int entryQuantity, ...other entry attributes)
Inventory inventory = inventoryRepository.findBy(inventoryId);
Entry entry = inventory.newEntry(entryQuantity, ..);
entry.handle();
inventoryRepository.store(inventory);
entryRepository.store(entry);
}
}
A 和 B 都是可行的,但是解决方案 B 有点不雅,因为在不涉及Entry的情况下会无意中调用Inventory .add(quantity) 。这是规则(每个事务只修改一个聚合实例)试图为我指出的吗?我很困惑为什么我们应该只修改事务中的一个聚合,如果我们不这样做会出现什么问题。
更新1开始
它是否打算缓解并发问题(使用“制作更小的聚合”的另一条规则)?例如,Entry是竞争相对较低的 Aggregate,而Inventory是竞争相对较高的聚合(假设多个用户可以操作一个Inventory),如果我在事务中同时修改它们,则会导致不必要的并发失败。
更新1结束
如果我采用解决方案A,还需要解决一些进一步的问题:
1.如果一个Inventory有很多Entry,我需要一个分页查询UI怎么办?如何使用集合实现分页查询?一种方法是加载所有Entry并选择页面需要的内容,另一种方法是 InventoryRepository.findEntriesBy(invoiceId, paging),但这似乎打破了仅通过获取本地实体来获取本地实体的规则,然后导航对象图.
2.如果一个Inventory的Entry太多,我必须在添加新Entry时加载所有这些怎么办?
我知道这些问题源于缺乏充分的理解。所以欢迎任何想法,在此先感谢。