Eric Evans的《领域驱动设计》问世已经14年之久,到今天几乎所有业务团队都或多或少有涉及DDD。然而如果较真会发现,认真遵循DDD设计原则的团队仍是少数,在多数团队的现都是:**领域模型=数据库关系。**DDD崇尚的是oo式表达,也就是常说的充血模型,对以关系型数据库实体关系为中心的关系模型甚至是可以用鄙夷来形容。

数据库关系模型

以数据库关系指导编程实践,是关系对程序的外延入侵,是预假设关系经存在再按图索骥将执行逻辑映射到关系,最终收口是落在数据库而非程序本身。程序本身成了一条条执行通道,每一条通道服务于特定场景的关系,后果必然是过程思维和面条代码。

假设有业务场景–向购物车添加商品,以关系为中心,代码组织如下:

public class CartLine{@Getter @Setterprivate String skuCode;@Getter @Setterprivate int buyNo;//数量
}public class CartServiceImpl implements CartService{public void addLine(String skuCode, int buyNo, ......){CartLine line= getLine(skuCode,  .....)if(line!= null){line.setBuyNo(buyNo);update(line);}else{new CartLineinsert}}
}

绝大多数人都应该会有类似代码的编写经历,最常见在经典三分层架构中的Service层,它本质上就是一个类存储过程,对其执行过程做翻译:

CartLine line= select * from cart_line where sku_code= #{skuCode}
if(line!= null){update cart_line set buy_no= #{buyNo} where sku_code= #{skuCode}
}else{insert cart_line values(xxxx)
}

业务处理就是在有序执行一条条sql,老外给它取了个好听的名字叫事务脚本。事务脚本是非常典型的过程式表述,类似是串联sql完成一段完整的业务,可以用求和数学公式“事务脚本=∑fi,fi代指一条sql”来定义

架构模式上管这种代码叫贫血模型,即无行为,表达力贫瘠。Martin Fowler在《企业应用架构模式》中

定义它是反模式,简单系统使用它开发没问题,而对于复杂业务,业务逻辑、各种状态散布在大量的函数中,维护扩展的成本会变得很高。

数据库中心的设计是”修改一处,全量回归“的悲剧源头,也是代码写久后枯燥、无聊、觉得都是重复劳动的源头。过程式代码并不需要精心设计和组织,自然写代码也就成了无意义的翻译器。

oo模型

假设内存无限大且永不宕机,即已经没有持久化必要,换句话说完全可以不使用数据库,此时应该如何编写代码?

  • 是使用与现实世界的活动实体做连接、特征和行为封装在一起,职责明确、逻辑合理分布的有状态对象,再按场景将合适类联系起来?
  • 还是使用仅映射活动实体特征的pojo,按场景忠实反应发生过程依次get/set操作pojo属性?

Jdk以及各类优秀中间件都是以内存操作为主,可以参考它们的选择:即便是主推pojo规范的ejb都没有选择贫血模型,反而是极度充血– 有行为,有联系、表达力强,容易组织。

数据持久化应只被当成是程序的暂停而非结束,对暂停而言,下一次再执行时需要忠实还原对象的上次执行后状态,而对结束则下一次是一个新的开始。即load; do;new; setter/getter; persist的区别。如果从这个角度出发,对象就变得近似是常驻在内存。

在Vaughn Vernon的《实现领域驱动设计》中关于“六边形架构”如何在领域实践应用中对数据库和DDD的关系有很清晰的阐述很:
数据库仅仅只是Domain Model的右向适配(被驱动者)。

数据库只是持久化手段,是一种基础设施,不该作为指导程序运行的模型。写代码时要时刻保持一种警惕,如果把关系型数据库替换成json、普通文本或者无schema的nosql数据库,要如何保证逻辑层的无感?

正确的方法是以对象和对象联系而非数据库表关系作为指导程序运行的基础。一次完整的业务操作由各实体对象行为协同完成,结果最终会反映在内存中各对象实例的内在属性上。这样无论怎么修改持久化方案,都只需要改变与特定持久化方案的适配策略。

某逆向交替系统,其逆向状态是记录在正向交易上的,

order_id order_status pay_fee item_id refund_amount refund_status attributes ……

refund_amount和refund_status分别代表逆向退款金额以及退款状态。很显然,这样的表设计会导致两个问题:1) 无法多次逆向,前一次状态在下一次发起后被覆盖,即逆向无法追溯;2)逆向需要更新交易订单属性,方式是调用交易接口更新,因此某些情况下可能会有乐观锁问题– 逆向更新了锁版本导致交易再去更新失败。

在小规模试跑阶段,业务上会严格限制一笔订单一次逆向,同时对于乐观锁问题采用多次重试机制,因此问题并不明显。逐渐的业务开始起来,首先业务量大之后重试导致的性能问题凸显– 在加事务的情况下,数据库连接是一直持有直到提交或回滚,多次重试相当于增加了几倍持有连接时间,因此会明显明显降低数据库吞吐;其次,对于不能多次逆向合作伙伴也开始有反弹。因此交易和逆向的表拆分变得势在必行。

因为逆向在设计时使用的充血+六边形架构,实际上迁移并没有很大工作量,只是重新建了表,然后对数据库适配进行修改,将输出表由A指向B。

而如果使用贫血模型,表结构有较大变更的情况下,则一定会要修改逻辑代码。可以使用事务脚本的公式做个简单的逆推导:
表变化=sql变化=事务脚本(逻辑执行)变化。

思辨领域模型-- DDD≠数据库关系模型相关推荐

  1. 思辨领域模型--DDD和关系型数据库

    为什么80%的码农都做不了架构师?>>>    摘要: Eric Evans的<领域驱动设计>问世已经14年之久,到今天几乎所有业务团队都或多或少有涉及DDD.然而较真起 ...

  2. ECMALL数据库关系模型的实现

    2019独角兽企业重金招聘Python工程师标准>>> 所谓模型,则是一个一个的数据实体,换句话说就是一个数据表,你可以基于这个模 型,调用model.base.php中的数据库操作 ...

  3. 第2章 数据库关系模型---数据库原理及应用

    目录 第2章        数据库关系模型 本章要求: 1.关系模型的基本概念 关系数据模型-现有主流DBMS支持的逻辑模型 域(Domain):相同数据类型的集合 关系模式:关系名和属性 关系实例: ...

  4. 【MySQL】使用Visio绘制数据库关系模型图

    使用Visio绘制数据库关系模型图 1 新建项目 文件-新建–软件和数据库-数据库模型图 点击后,出现如下界面: 2 绘制 左侧"实体关系"中将"实体"形状拖放 ...

  5. 数据库关系模型与关系运算---2022.2.13

    关于外模式,模式,内模式的理解 可以看到用不同的语句进行表示: 关系的性质 概念模式/内模式映射是物理独立性的关键: 外模式/概念模式映射就是逻辑独立性的关键 候选键 (最小组成的超键) 关系中的一个 ...

  6. 数据库关系模型的三类完整性约束

    关系模型中有三类完整性约束,分别是:实体完整性,参照完整性,用户定义完整性 实体完整性 定义:实体完整性是用于保证关系数据库中每个元组都是可区分的,唯一的. 它的意思就是说数据表中每一行都应该有办法将 ...

  7. 数据库 ---- 关系模型

    在关系模型中,操作的对象和结果都是二维表,关系模型是目前最流行的数据库模型.支持关系模型的数据库管理系统称为关系数据库管理系统,Access就是一种关系数据库管理系统. 1.基本术语 (1)关系(Re ...

  8. 数据库关系模型和关系运算[姊妹篇.第三弹]

    随着ORM框架的日益流行,如今的码农们直接操作数据库语法的越来越少了,一顿orm语法操作猛如虎,一遇问题问题便靓仔语塞.这种情况不在少数,就如我的工作中,我所知道的同事和实习生当中,就有不少人非常喜欢 ...

  9. 数据库关系模型有哪三类完整性约束?

    一.实体完整性 实体完整性要求每个表都有唯一标识符,每一个表中的主键字段不能为空或者重复的值. 二.参照完整性 参照完整性要求关系中不允许引用不存在的实体.设定相应的更新删除插入规则来更新参考表. 例 ...

最新文章

  1. 去除ios input部分默认样式
  2. 网络工程师_想要记录下来的一些题_2
  3. ntp服务器源码c语言,搭建自己的NTP时间服务器
  4. 从新浪财经上下载交易明细数据并统计每天的买卖笔数(shell 命令行)
  5. linux 权限777_Linux编程之权限系统与工具使用(二)
  6. .NET应用迁移到.NET Core(一)
  7. Linux—程序包安装与管理
  8. cas登录后怎么直接到我们系统_当我们购买服务器后,那么服务器的操作系统该怎么选择呢?...
  9. 华为eNSP的基础入门实验
  10. 再见了,收费的XShell,我改用国产良心工具!
  11. 全网最全最细的PLSQL下载、安装、配置、使用指南、问题解答,相关问题已汇总
  12. 梯度(gradient)
  13. 网页无插件播放RTSP流媒体
  14. PowerDNS Authoritative Server 3.2 RC3 发布
  15. 腾讯云播放器隐藏音频播放的按钮
  16. 华硕双路服务器主板装系统,华硕双路服务器主板Z8PE-D12X
  17. H5 -- 自定义微信分享第三方页面链接的标题和小缩略图
  18. 不仅是工程学!人类认知偏差导致的12个AI研究盲区
  19. OC语言——基本语法和思想
  20. PPT在线预览 转换为图片实现方案 Apache POI 实现时踩坑:含嵌入文件ppt转换报错 ArrayStoreException

热门文章

  1. 怎样招聘一名博士毕业生?
  2. 微信公众号支付验证签名失败及其它坑总结
  3. 微信:支付验证签名失败
  4. 计算机三级嵌入式学习笔记(二)
  5. java 手机号运营商号段正则匹配(长期更新)
  6. git创建局域网内的远程仓库
  7. 监控系统加装存储服务器,监控系统加装存储服务器
  8. web中的图片(img/background)操作
  9. 移动互联网4种引流思维:免费思维、跨界思维、平台思维、金融思维
  10. 医学图像与生物模型处理软件MedSys1.0