2. 领域驱动设计基础:实体、值对象、聚合、领域事件、限界上下文在数据建模中的映射关系
领域驱动设计(DDD)为复杂业务系统的数据建模提供了战略与战术层面的指导。将 DDD 的核心概念映射到数据库模型,是构建高内聚、低耦合、可演进数据架构的关键。本章将逐一剖析实体、值对象、聚合、领域事件与限界上下文在数据层面的具体映射规则。
2.1 实体(Entity)的数据库映射
实体具有唯一标识和连续的生命周期。在数据模型中,实体通常映射为一张独立的数据库表,其主键即为实体的唯一标识。
| DDD 概念 | 数据库映射 | 关键约束 |
|---|---|---|
| 实体(Entity) | 独立表(Table) | 必须有主键(PK),通常为业务自然键或代理键(UUID/自增ID) |
| 唯一标识(Identity) | 主键列(Primary Key) | 不可变,全局唯一,禁止业务含义变更导致主键重写 |
| 属性(Attribute) | 普通列(Column) | 直接映射为字段,类型与长度需与领域约束对齐 |
| 行为(Behavior) | 存储过程/触发器(可选) | 推荐在应用层实现,数据库仅保证数据完整性 |
实践建议: 实体表的主键尽量使用代理键(如 UUID),避免因业务自然键(如身份证号、手机号)变更导致级联更新。代理键应作为内部标识,业务唯一性通过唯一索引(UNIQUE)约束实现。
2.2 值对象(Value Object)的数据库映射
值对象通过属性值定义自身,没有唯一标识,且不可变。在数据建模中,值对象有两种主流映射方式:嵌入式(Embedded) 和 独立表(Separate Table)。
- 嵌入式映射: 将值对象的属性直接展开为实体表的多个列。适用于一对一、低频复用的值对象(如地址、货币金额)。
- 独立表映射: 将值对象单独建表,通过外键关联实体。适用于一对多、高频复用的值对象(如订单行项目中的商品快照)。
| 映射方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 嵌入式 | 值对象与实体生命周期强绑定,且不单独查询 | 查询无需 JOIN,性能高;模型简单 | 值对象复用困难;列数膨胀 |
| 独立表 | 值对象需要被多个实体共享,或需要独立查询 | 数据冗余低;值对象可独立演进 | 查询需 JOIN;需处理外键约束 |
映射原则: 值对象在数据库中不应拥有独立的主键。若采用独立表,应使用复合主键(实体外键 + 值对象业务键)或代理键,但代理键仅用于物理存储,不暴露给领域层。
2.3 聚合(Aggregate)与数据一致性边界
聚合是数据一致性的最小单元。一个聚合包含一个根实体(Aggregate Root)和若干实体/值对象。在数据库层面,聚合映射为一组具有强引用关系的表集合,聚合根表作为入口。
关键约束: 一个事务只应修改一个聚合。跨聚合的数据一致性应通过领域事件或最终一致性(Saga/事件溯源)实现,而非依赖数据库外键级联。聚合边界内的表可以共享同一个数据库事务。
2.4 领域事件(Domain Event)的数据持久化
领域事件记录聚合中发生的业务事实,用于解耦聚合间的通信。在数据模型中,领域事件通常映射为事件存储表(Event Store) 或 消息表(Outbox Table)。
- 事件存储表: 用于事件溯源(Event Sourcing),存储所有历史事件,作为系统状态的权威来源。
- 消息表(Outbox): 用于可靠消息投递,保证本地事务与消息发送的原子性。
| 用途 | 表结构核心字段 | 典型场景 |
|---|---|---|
| 事件溯源 | event_id, aggregate_id, event_type, event_data (JSON), version, occurred_on | 订单状态机、账户流水 |
| 事务性发件箱 | id, aggregate_id, event_type, payload, created_at, processed_at | 跨服务异步通知、CQRS 同步 |
映射原则: 领域事件表应设计为仅追加(Append-Only),禁止更新或删除历史事件。事件数据建议使用 JSON/JSONB 格式存储,以支持灵活的事件结构演进。
2.5 限界上下文(Bounded Context)的数据库边界
限界上下文是 DDD 的战略设计核心,定义了模型、语言和业务能力的边界。在数据层面,每个限界上下文应拥有独立的数据库实例或独立的 Schema,禁止跨上下文直接访问表。
数据隔离策略:
- 独立数据库: 适用于微服务架构,物理隔离最强,但运维成本高。
- 独立 Schema: 适用于单体应用内的模块化,逻辑隔离,共享数据库实例。
- 禁止跨上下文 JOIN: 数据查询必须通过 API 或事件驱动获取,避免数据库层面的紧耦合。
2.6 映射关系总结
| DDD 概念 | 数据建模映射 | 核心关注点 |
|---|---|---|
| 实体 | 独立表 + 主键 | 标识稳定性、生命周期管理 |
| 值对象 | 嵌入式列 / 独立表(无独立主键) | 不可变性、复用性、查询性能 |
| 聚合 | 一组表(聚合根表 + 子表) | 事务边界、一致性单元 |
| 领域事件 | 事件存储表 / 发件箱表 | 仅追加、不可变、事件溯源 |
| 限界上下文 | 独立数据库 / 独立 Schema | 数据隔离、无跨上下文 JOIN |
核心原则: 数据模型是领域模型的忠实投影,而非技术实现的附属品。每一次数据库表结构的设计决策,都应回归到 DDD 概念所表达的业务语义和一致性边界上。只有坚持这种映射关系,才能构建出既满足业务需求、又具备长期演进能力的数据库架构。