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)和若干实体/值对象。在数据库层面,聚合映射为一组具有强引用关系的表集合,聚合根表作为入口。

聚合在数据库中的映射边界 聚合根:订单表 PK: order_id 实体:订单项表 PK: order_item_id, FK: order_id 值对象:地址(嵌入式) 展开为订单表列 聚合边界(事务一致性) • 订单与订单项通过外键强关联 • 地址作为值对象嵌入订单表 • 跨聚合引用仅通过聚合根 ID 聚合根:客户表 PK: customer_id 引用 customer_id
关键约束: 一个事务只应修改一个聚合。跨聚合的数据一致性应通过领域事件或最终一致性(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: order_service 库存上下文 库存表 库存流水表 Schema: inventory_service 支付上下文 支付单表 事件存储表 Schema: payment_service 事件 事件
数据隔离策略:
  • 独立数据库: 适用于微服务架构,物理隔离最强,但运维成本高。
  • 独立 Schema: 适用于单体应用内的模块化,逻辑隔离,共享数据库实例。
  • 禁止跨上下文 JOIN: 数据查询必须通过 API 或事件驱动获取,避免数据库层面的紧耦合。

2.6 映射关系总结

DDD 概念 数据建模映射 核心关注点
实体 独立表 + 主键 标识稳定性、生命周期管理
值对象 嵌入式列 / 独立表(无独立主键) 不可变性、复用性、查询性能
聚合 一组表(聚合根表 + 子表) 事务边界、一致性单元
领域事件 事件存储表 / 发件箱表 仅追加、不可变、事件溯源
限界上下文 独立数据库 / 独立 Schema 数据隔离、无跨上下文 JOIN
核心原则: 数据模型是领域模型的忠实投影,而非技术实现的附属品。每一次数据库表结构的设计决策,都应回归到 DDD 概念所表达的业务语义和一致性边界上。只有坚持这种映射关系,才能构建出既满足业务需求、又具备长期演进能力的数据库架构。