【问题标题】:DDD and business rules that need ACIDDDD和需要ACID的业务规则
【发布时间】:2020-07-26 01:14:09
【问题描述】:

我理解它的方式:您将数据库中的所有数据加载到您的业务逻辑所在的实体中。这就像在当前用例的内存中拥有数据库的副本。

但我看不到如何执行需要数据库 ACID 的逻辑。 例如,如果我们使用银行应用程序的示例。

您如何确保提款不会超过账户余额? 如果客户在两台不同的计算机上登录网站,则在两个会话中都提取有效金额。

他有一点机会可以提取两倍的钱。

这种业务应该如何处理?

【问题讨论】:

  • 无论您在前端显示什么,您都应该假设用户可以更改它或者它不会是最新的。对于任何类型的实际交易,您必须在执行之前在后端检查它,然后使用新的数据库状态(银行余额或其他)更新前端。将您的前端简单地视为数据的缓存显示版本,可能是最新的,也可能不是最新的。
  • @joshstrike 忘记前端。想象两个尝试提取资金的 API 端点调用。
  • @adele 当您开始处理每个 api 调用时,您将启动一个数据库事务。然后您可以使用任一悲观锁 - 然后第二个调用将等到第一个调用完成。例如,或乐观锁来验证帐户上预期的最后一个 tx id。这样,您将使用数据库的内置事务保证来确保数据一致性。
  • 但由于银行业涉及许多分布式操作,它们(或任何实际业务)很少提供 ACID 保证。因此存在技术透支。但必须确保的是 - 在您的示例中是现金提取的幂等性。
  • 没错。在最坏的情况下,第二个将完成,但稍后会回滚,因为您没有足够的资金来真正做到这一点。

标签: entity-framework domain-driven-design ddd-repositories


【解决方案1】:

如果最终一致性(即数据将在某个时刻再次保持一致 - 最终)不是一个选项,那么您确实需要一致性对于特定的业务实体,您需要确保在在您的域模型上应用业务逻辑之前启动一些事务。

这意味着在交易期间也会读取银行账户余额的当前状态,同时不允许更新银行账户余额。

这些类型的事务可以在技术上应用在一个服务中,例如,通过数据库事务。但是这样的业务交易一次应该只涉及一个聚合对象。

回到你的问题:

您如何确保提款不会超过账户余额?

以银行账户为例,可以假设(取决于银行的业务不变量)账户余额不得低于零或至少不得低于商定的透支限额。因此必须在交易中保留要提取的金额

但是将保留金额转移到另一个账户只需要最终保持一致,并且可以稍后在另一个交易中发生(然后在另一个聚合账户对象上执行),以确保这也只发生一次。

注意:事务也可以通过应用诸如 Saga Pattern 之类的模式跨多个微服务应用。

【讨论】:

    猜你喜欢
    • 2014-08-16
    • 2021-05-03
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 2019-05-29
    • 2017-11-08
    • 2020-05-16
    • 1970-01-01
    相关资源
    最近更新 更多