DDD与数据库

索引失效

  • 联合索引不满足最左匹配原则
  • 索引列参与运算、使用了函数
  • 错误的like(有总结,是否涉及到 覆盖索引)
  • 类型隐式转换
  • 两列数据做比较,即便两列都创建了索引,索引也会失效。
  • 负向查询:不等于比较:<> !=、is not null、not in
    • 查询条件使用not in时,如果是主键则走索引,如果是普通索引,则索引失效。
    • 查询条件使用not exists时,索引失效
  • order by导致索引失效
  • 当查询条件为大于等于、in等范围查询时,根据查询结果占全表数据比例的不同,优化器有可能会放弃索引,进行全表扫描

回表:就是先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树

覆盖索引:是select的数据列只用从索引中就能够取得,不必读取数据行

联合索引:(id, text_info)


image.png

联合索引:(name, text_info)


image.png

索引:(headicon)、(text_infov)


image.png

=================================================

领域、限界上下文的有关数据库设计

  • 领域更偏向战略层面,“相同”的数据在不同的领域中

  • 比如,

    1. 售卖域和订单域中的“商品”,逻辑上不一样,在数据的组织上也可能不一样。

      两个领域绝大多数做服务拆分,在数据库上的表现是各自服务下的管理各自逻辑的表。

    2. 售卖域中,有售卖上下文和秒杀上下文,“商品”在这两个上下文中是否有各自的限定?限界上下文可以指导数据库的设计

实体、值对象

  • 对比:

    • 实体是唯一的且可持续变化的
    • 值对象:表示一个具体的概念、属性判等、固定不变
  • 举例:

    • 上述的例子中售卖域和订单域的“商品“,可以假设售卖域中的商品是唯一、有上架下架等状态的实体;订单域中的”商品“是订单实体的值对象,一对多的关系

      • 在数据库上的表现,
        • ”商品“实体有相关的状态、id等字段;
        • ”商品“值对象可以没有这些字段。
    • 售卖上下文和秒杀上下文例子中,”商品“是不同的限界上下文下的两个不同的实体

      数据库可以表现:拆分成秒杀商品表和售卖商品表,或,可以维护商品基本信息表取join秒杀状态表和售卖状态表

  • 实体持久化问题:

    • 通过依赖倒置的方式,将接口放在domain的聚合包下的gateway(防腐层),在infrastructure。在application层的command中进行持久化操纵

聚合

聚合是领域对象的显式分组,旨在支持领域模型的行为和不变性,同时充当一致性和事务性边界。

聚合不仅仅是简单的对象组合,其主要的目的是用来封装业务和保证聚合内领域对象的数据一致性。

  1. 领域对象的显式分组

  2. 领域行为和不变性

    1. 领域不变性指的是必须遵守的陈述或规则。换句话说,就是领域内我们关注的业务规则。

      比如,订单必须具有唯一订单编号、订单日期;订单必须冗余商品的基本信息(名称、价格、折扣);订单至少有一个商品,删除商品时,订单项需要一并删除;等等。(假设的需求,实际上不会让没有商品)

前两句话综合来说,就是聚合通过对领域对象的封装来体现领域中的业务规则。

  1. 一致性和事务性边界

举例说明一致性、事务问题:

  1. 传统的做法:在一个事务中,订单从未支付状态更新为已支付状态,需要扣库存

    1. 存在问题:并发冲突

      如,更新订单时;此时恰逢进货,需要增加库存;这样存在潜在冲突

    2. 从DDD的角度进行问题剖析:将业务涉及到的所有领域对象都放到了一个事务性边界中

  2. 聚合的事务

    DDD理论学习系列(10)-- 聚合 - (jianshu.com)

    关于领域驱动设计(DDD)中聚合设计的一些思考 - 反光的小鱼儿 - 博客园 (cnblogs.com)

    深入了解 CQRS — 一个伟大的微服务模式 - 知乎 (zhihu.com)

    CQRS 模式 - Azure Architecture Center | Microsoft Docs

应用服务和领域服务

如何分辨应用服务与领域服务 | 张逸说 (zhangyi.xyz)

  • 应用服务:包含领域逻辑的业务服务

  • 领域服务:

    1. 与横切关注点(AOP)协作的服务应被定义为应用服务
    2. 不包含领域逻辑的业务服务应被定义为应用服务。
  • 如,

    • 日志、异常处理根据具体的粒度,来决定在哪一层的服务
    • 短信通知,一般不会涉及到核心领域逻辑,是一种横切关注点
    • 验证的逻辑是否涉及到领域逻辑,来决定在哪一层
    • 服务调用,一般服务调用时涉及到领域逻辑的,通过依赖倒置,接口放在domain,实现放到infrastructure
  • 关于持久化的问题,领域逻辑应该只关心业务逻辑,才能保证领域逻辑的可重用性。应将持久化放到应用层。

    分包中的体现,类似于 domain聚合根包下的持久层依赖倒置

仓储

  • 仓储代表一个聚合的集合,仓储用来存储和删除聚合,同时提供针对聚合的显式查询以及汇总

    仓储的使用在上实体持久化中描述

  • 特点:

    • 只能通过聚合根来持久化和查询领域对象
    • 仓储隐藏了聚合持久化和查询的底层技术
    • 仓储在数据模型和领域模型定义了一个边界
  • 事务:单一职责原则,仓储不能取管理事务

  • 理解:

    • 仓储用于管理单个聚合,不应该控制事务。
    • 仓储实现了透明持久化
    • 仓储像契约,使用ORM提供的数据模型(DAL通过PO持久化或查询)实现domain的仓储接口

======================================================================
聚合的事务

  1. 要维护各自子域内业务规则的不变性,而不是为了业务场景实现一概而论。把支付、订单、售卖拆为三个独立的聚合,

    1. 各自的聚合管理各自的内部事务一致性

    2. 聚合和聚合之间的事务一致性 通过上述的领域事件来实现

      支付聚合发布支付成功的领域事件,订单、售卖订阅事件

      (具体的实现涉及到更多东西)

      关于领域驱动设计(DDD)中聚合设计的一些思考

      深入了解 CQRS — 一个伟大的微服务模式 - 知乎 (zhihu.com)

      事件溯源模式 - Azure Architecture Center | Microsoft Docs

  2. 聚合:

    1. 遵循领域不变性,在一个聚合中仅修改一个聚合

    2. 聚合内实现事务一致性,聚合外实现最终一致性

你可能感兴趣的:(DDD与数据库)