基于DDD的复式记账账本聚合根设计与余额存储方案求解
适配QLDB特性的DDD折中设计方案
核心设计前提
保留原有的两个独立聚合根划分:
LedgerEntry作为聚合根,内部持有所有关联的LedgerLine实体,创建时强制校验借贷平衡规则LedgerAccount作为独立聚合根,支持单独的增删改查操作,LedgerLine仅存储关联的LedgerAccountID
具体实现逻辑
利用QLDB原生多文档ACID事务突破聚合根更新限制
DDD中「单次事务不能更新多个聚合根」的规则本质是规避跨存储节点的分布式事务一致性风险,而QLDB原生支持单事务内多文档的原子更新,完全可以在同一个ACID事务内完成以下操作:- 基于乐观锁查询所有分录关联的
LedgerAccount,携带版本号字段校验数据是否为最新状态 - 校验所有涉及余额扣减的账户余额满足最低要求(避免透支)
- 写入新的
LedgerEntry及其关联的所有LedgerLine - 批量更新所有关联
LedgerAccount的余额和版本号
该操作完全保证原子性,不会出现分录创建成功但余额未更新、或者余额更新失败但分录已生效的问题,同时规避了异步更新导致的余额延迟问题。
- 基于乐观锁查询所有分录关联的
增加一致性兜底校验机制
异步启动定时/触发式校验任务:针对发生过余额变动的账户,定期拉取指定时间段内的所有LedgerLine计算余额,和LedgerAccount上持久化的余额做比对,出现不一致立刻触发告警,避免极端场景下的数据异常。余额快照辅助优化
每月定时为所有账户生成当月初的余额快照,后续如果需要做全量余额校验,仅需要从快照时间点之后的LedgerLine开始计算即可,无需扫描全量历史明细,彻底解决大数量级下的计算性能问题。
矛盾点匹配解决说明
- 跨聚合根更新:基于QLDB原生ACID事务实现,无分布式事务风险,不违背DDD一致性设计的核心诉求
- 异步更新余额透支问题:余额更新和分录创建在同一事务内完成,读取到的永远是最新余额,完全避免透支风险
- 账户无法单独操作:
LedgerAccount始终是独立聚合根,增删改查操作不受任何影响 - 全量计算性能问题:余额直接持久化存储,日常查询无需计算,配合快照做校验也不会出现全量扫描的性能瓶颈
内容的提问来源于stack exchange,提问作者ljiatu
相关产品推荐
相关产品推荐

