Domain driven design 如何在CQRS中建立银行转账模型
我正在阅读,对在CQRS中实现它很好奇 我认为AccountingTransaction是一个聚合根,因为它保护不变量: 没有资金泄漏,应该从一个帐户转移到另一个帐户。Domain driven design 如何在CQRS中建立银行转账模型,domain-driven-design,cqrs,event-sourcing,Domain Driven Design,Cqrs,Event Sourcing,我正在阅读,对在CQRS中实现它很好奇 我认为AccountingTransaction是一个聚合根,因为它保护不变量: 没有资金泄漏,应该从一个帐户转移到另一个帐户。 public class AccountingTransaction { private String sequence; private AccountId from; private AccountId to; private MonetaryAmount quantity; priv
public class AccountingTransaction {
private String sequence;
private AccountId from;
private AccountId to;
private MonetaryAmount quantity;
private DateTime whenCharged;
public AccountingTransaction(...) {
raise(new AccountingEntryBookedEvent(sequence, from, quantity.negate(),...);
raise(new AccountingEntryBookedEvent(sequence, to, quantity,...);
}
}
将AccountingTransaction添加到其存储库时。它发布多个AccountingEntryBookedEvent,用于更新查询端相应帐户的余额
每个db事务更新一个聚合根,最终的一致性,到目前为止还不错
但是,如果某些帐户应用转移约束,例如不能转移数量超过当前余额,该怎么办?我可以使用查询端获取帐户余额,但我担心来自查询端的数据过时了
public class TransferApplication {
public void transfer(...) {
AccountReadModel from = accountQuery.findBy(fromId);
AccountReadModel to = accountQuery.findBy(toId);
if (from.balance() > quantity) {
//create txn
}
}
}
我应该在命令端对帐户建模吗?我必须为每个db事务更新至少三个聚合根(从/到帐户和帐户txn)
有些用例不允许最终的一致性。CQRS很好,但数据可能需要100%一致。CQR并不意味着/要求最终一致性
但是,事务/域模型存储将保持一致,并且该存储中的余额将保持一致,因为它表示当前状态。在这种情况下,不管查询端是否不一致,事务都应该失败。这将是一种有点奇怪的用户体验,尽管如此,100%一致的方法可能更好。我记得其中的一些内容,但是M Fowler使用的事件含义与域事件不同。他使用了“错误”的术语,因为我们可以在他的“事件”定义中识别命令。所以基本上他说的是命令,而域事件是已经发生的事情,它永远不会改变 可能我没有完全理解Fowler所指的,但我会以不同的方式建模,更精确地尽可能接近领域。我们不能简单地提取一种模式,这种模式可以应用于任何金融应用程序,细微的细节可能会改变一个概念的含义 在OP的例子中,我认为我们可以有一个非显式的“交易”:我们需要一个借记金额的账户和另一个贷记金额相同的账户。我认为,最简单的方法是通过一个传奇故事来实现它 借记账户->借记账户->贷记账户->贷记账户->贷记账户=交易完成 这应该在几毫秒内发生,最多几秒钟,这将足以更新读取模型。人类和浏览器的速度比几秒钟还要慢。用户知道按F5或等待几分钟/小时。我不会太担心读取模型的准确性 如果事务是显式的,即域具有事务概念,并且业务确实存储了事务,那么情况就完全不同了。但即使在这种情况下,交易也可能由多个帐户id和一些金额以及一个完成标志来定义。然而,在这一点上继续下去是没有意义的,因为它实际上取决于域的定义和用例。只有两个字:“保留模式”。
也许,但并非总是,您也可能需要“”模式。修复了答案 最后,我的解决方案是将事务作为域模型
并将交易投影到AccountBalance,但我实施了特殊投影,以确保在发布实际事件之前所有数据的一致性。是否希望bankapplication使用DDD?@Singh感谢您的评论。是的,CQRS的DDD。我有一个关于银行申请的项目。“你想要吗?”辛格我想看看,谢谢。你可以通过电子邮件发送(hippoom@gmail.com)如果你方便的话,你的答案在哪里(
public class TransferApplication {
public void transfer(...) {
Account from = accountRepository.findBy(fromId);
Account to = accountRepository.findBy(toId);
Transaction txn = new Transaction(from, to, quantity);
//unit or work locks and updates all three aggregates
}
}
public class AccountingTransaction {
public AccountingTransaction(...) {
if (from.permit(quantity) {
from.debit(quantity);
to.credit(quantity);
raise(new TransactionCreatedEvent(sequence, from, to, quantity,...);
}
}
}