You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

领域驱动设计中聚合、事务与并发:项目成员约束失效求解

聚合根事务边界问题探讨(TypeORM + PostgreSQL Serializable隔离级别)

场景背景

基于TypeORM与PostgreSQL,采用Serializable隔离级别(注:此隔离级别与TypeORM事务管理机制相关)。

业务规则:

  • Project 作为聚合根,可包含任意数量的 Member
  • 每个 Member 拥有角色,一个项目最多只能有3个Admin角色的成员

Project 类代码示例:

class Project {
  private readonly members: Member[] = [];
  addMember(userId: string, role: string) {
    // 若角色为Admin,校验当前Admin数量(此处代码仅示意逻辑)
    this.members.push(new Member(userId, role));
  }
}

为确保不变量约束,所有成员需一次性加载至内存后操作(假设成员数量较少)。

并发冲突问题

当项目已有2个Admin成员时,两名用户同时执行以下操作:

执行流程1

const project = projectRepository.getById(projectId);
project.addMember({ userId: "xxx", role: "Admin" });
projectRepository.save(project);

执行流程2

const project = projectRepository.getById(projectId);
project.addMember({ userId: "yyy", role: "Admin" });
projectRepository.save(project);

两个流程通过TypeORM生成的事务均为:

BEGIN;
INSERT INTO members (user_id, role) values ('zzz', 'ADMIN');
COMMIT;

最终两个事务都执行成功,导致项目出现4个Admin成员,破坏了最多3个Admin的不变量约束。

现有解决方案思路

方案1 - 自定义事务:删除重插所有成员

每次保存项目时,先删除该项目的所有成员记录,再重新插入全部成员。此方案可在分布式环境下保护不变量约束。

对应的事务SQL:

BEGIN;
DELETE FROM members WHERE project_id = 'aaa';
-- 插入所有成员的语句
COMMIT;

方案2 - 调整聚合边界

若方案1不合理,当前的聚合边界无法提供有效事务约束。可考虑将 Member 设为独立聚合根,每次添加成员时直接校验该项目的Admin数量是否超过3,必要时配合分布式锁使用。

疑问

我是否遗漏了其他更合理的解决方案?期待各位的见解!

注:已尝试多种基于TypeORM的事务处理方式,此问题兼具实践与理论探讨价值。


内容的提问来源于stack exchange,提问作者Ricardo Ferraris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:53:26