【DDD】学习笔记-数据实现模型

news2024/11/18 20:02:24

SQL 与存储过程

倘若选择关系型数据库,组成数据实现模型的主力军是 SQL 语句,这是我们不得不面对的现实。毕竟,针对数据建模的实现者大多数担任 DBA 角色,他(她)们掌握的操作数据的利器就是 SQL。正如前面讲解数据分析模型时所说,SQL 语句相当于是操作关系数据表的领域特定语言(Domain Specific Language,DSL),使用 SQL 操作数据表更加直接而自然。

SQL 语句可以很强大,例如它同样提供了数据类型、流程控制、变量与函数定义。同时,还可以使用 SQL 来编写存储过程。从某种程度讲,存储过程也可以认为是事务脚本。如下的存储过程就封装了插入论坛类别的业务过程:

CREATE PROCEDURE np_Forums_InsertCategory
@CategoryName    varchar(100),
@CategoryImageUrl    varchar(100),
@CategoryPosition    int,
@CategoryID        int OUTPUT

AS
DECLARE @CurrID int
-- see if the category already exists
SELECT @CurrID = CategoryID
    FROM Forums_Categories
    WHERE CategoryName = @CategoryName
-- if not, add it

IF @CurrID IS NULL
    BEGIN
    INSERT INTO Forums_Categories
        (CategoryName, CategoryImageUrl, CategoryPosition)
        VALUES (@categoryName, @CategoryImageUrl, @CategoryPosition)
    SET @CategoryID = @@IDENTITY
    IF @@ERROR > 0
        BEGIN
        RAISERROR ('Insert of Category failed', 16, 1)
        RETURN 99
        END
    END

ELSE
    BEGIN
    SET @CategoryID = -1
    END

在我踏上软件开发道路之初,无论是讲解数据库编程的书籍,还是身边的资深程序员,都在告诉我应当优先考虑编写存储过程来封装访问数据的逻辑。在开发数据库管理系统的时代,这似乎成为了性能优化的箴言,然而这并非事实的真相。Eric Redmond 在《七周七数据库》中就写道:

“存储过程可以通过巨大的架构代价来取得巨大的性能优势。使用存储过程可以避免将数千行数据发送到客户端应用程序,但也让应用程序代码与该数据库绑定,因此,不应该轻易决定使用存储过程。”

我曾经经历过将 Sybase 上的大量存储过程迁移到 Oracle 的噩梦,也曾阅读和维护过长达二千多行的存储过程,真可以说是往事不堪回事,这使得我对存储过程始终抱有戒惧心理。Donald Knuth 于 1974 年在 ACM Journal 上发表的文章 Structured Programming with go to Statements 中写道:

“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.”

显然,在我们没有通过性能测试发现性能瓶颈之前就进行的性能优化,可谓“万恶之源”。存储过程确有性能优势,但在没有发现性能瓶颈时,因为性能而选择存储过程,意味着会牺牲代码的可维护性、可读性及可扩展性,带来的结果可能是得不偿失。

在分布式系统下,SQL 存储过程带来的性能优势消散殆尽。单机版的时代已经过去。当数据量与访问量变得越来越大时,存储过程带来的性能提升已经不足以解决性能问题。由于存储过程强耦合于数据库服务器,使得对它的改造受到了诸多限制。例如,根据 AKF 的立方体模型,若要实现系统的可伸缩性(Scalability),可以从三个维度对系统的对应层次进行分割:

35156314.png

评估立方体的三个维度:

  • X 轴的可伸缩性代表了数据或服务的复制与负载均衡:数据层采用数据库集群以及读写分离来保证。此时,存储过程不会受到 X 轴分割的影响。
  • Y 轴的可伸缩性代表了服务的切分:相当于采用微服务架构。为了避免数据库出现性能瓶颈,应遵循微服务的设计原则,保证每个微服务有专有的数据库。若拆分前的单体架构使用了存储过程,可能包含大量多表关联,当迁移到微服务架构时,可能因为分库的原因,需要对存储过程做出修改和调整。
  • Z 轴的可伸缩性代表了数据的分片:这意味着需要针对同类型的数据进行分库,如果 SQL 封装在服务或数据访问对象中,可以通过类似 ShardingSphere 这样的框架对 SQL 进行自动解析,满足分库分表的能力;但如果是存储过程,就会受到影响。

不管是 SQL 语句还是由 SQL 语句构成的存储过程,更擅长表达对数据表和关系的操作。例如一些跨表查询通过 SQL 的 JOIN 或者子查询会显得更加直接,查询条件用 WHERE 子句也极为方便,但在针对复杂的业务逻辑处理,SQL 的表达力就要远远弱于类似 Java 这样的语言了。

SQL 和存储过程的自动化测试一直是一个难题。虽然有的数据库提供了 SQL 单元测试的开发工具,例如 Oracle SQL Developer;但是,单元测试的本质是不依赖于外部资源,SQL 的目的又是访问数据库,这就使得 SQL 单元测试本身就是一个悖论。类似 STK/Unit 这样的工具可以通过编写测试脚本来实现 SQL 的自动化测试,但实际上它是通过编写存储过程来调用测试用例,因而具有存储过程天然的缺陷。SQL 的代码调试也是一个非常大的问题。总之,一旦业务需求变得越来越繁杂,又或者业务需求频繁发生变化,维护 SQL 与存储过程会变得极为痛苦。

如果使用关系数据库,唯一绕不开的 SQL 场景是数据库的创建,以及基础数据的生成。软件系统一旦上线投入到生产环境,最难以更改的其实是数据库,包括数据库样式和已有的数据。无论是升级还是迁移,数据库都是最复杂的一环。为了解决这一问题,就需要对数据库脚本进行版本管理。无论变更是大还是小,是影响数据库样式还是数据,每次变更都应该放在单独的脚本文件中,并进行版本控制。这就相当于为数据库标记了检查点(Checkpoint),使得我们既可以从头开始部署数据库环境,也可以从当前检查点开始升级或迁移。像 FlywayDB 框架就规定每次数据库变更都定义在一个单独的 SQL 文件中,文件名前缀为:V{N}__,N 代表版本号。例如:

80267566.png

即使是一次小的变更,也应该在带有版本号的 SQL 脚本中体现出来,例如上图中的 V19 脚本,其实就是在 t_fields 表中添加了一个新列:

ALTER TABLE t_fields ADD COLUMN format VARCHAR(200);

当然,考虑到升级失败时的回退,还应该提供对应的回退脚本:

ALTER TABLE t_fields DROP COLUMN format;

对象关系映射

我在介绍数据设计模型时提到数据表与对象之间的关系,认为:

一种简单直接的方法是建立与数据表完全一一对应的类模型。

这其实是数据模型驱动设计的核心原则,即它是按照数据表与关系来建模的,因此在数据模型驱动设计中,数据表与对象的映射非常简单:数据表即类型,一行数据就是一个对象。映射的持久化对象是一个典型的贫血模型。如果针对关系数据库建立了数据模型,却在定义对象类型时采用了面向对象的设计思想,那就不再是数据模型驱动,而是领域模型驱动。

数据表与对象之间的映射,主要体现在概念上的一一对应,对于关系的处理则有不同之处。Jimmy Nilsson 认为:

“在关系数据库中,关系是通过重复的值形成的。父表的主键作为子表的外键重复,这就有效地使子表的行‘指向’它们的父亲。因此,关系模型中的一切事物都是数据,甚至关系也是数据。”

在类模型中,这种主外键关系往往通过类的组合或聚合来体现,即一个对象包含了另外一个对象或对象的集合。注意,这里的聚合是面向对象设计思想中的概念,并非领域驱动设计中的聚合。因此,当数据访问对象从数据表中查询获得返回结果时,需要通过映射器来实现从数据表的行到对象的转换。

整体而言,当我们面对关系数据库进行数据建模时,数据实现模型实际上得到了简单处理,所有业务都通过服务、数据访问对象与持久化对象三者之间的协作来完成,三者各司其职:

  • 持久化对象就是数据表的映射,并合理处理数据表之间的关系;
  • 数据访问对象负责访问数据库,并完成返回结果集如 ResultSet 或 DataSet 到持久化对象的映射;
  • 服务利用事务脚本或者存储过程来组织业务过程。

当然,持久化对象与数据访问对象的组合可以有多种变化,我在前面讲解数据设计模型时已经介绍,这些变化对应的恰好是 Martin Fowler 在《企业应用架构模式》中总结的四种数据源架构模式:

  • 表入口模式
  • 行入口模式
  • 活动记录
  • 数据映射器

这种简单的职责分配可以让一个不具备面向对象设计能力的开发人员快速上手,尤其是在 ORM 框架的支持下,框架帮助开发人员完成了大部分工作:生成持久化对象,封装通用的数据访问行为,利用元数据或配置完成表到类的映射。留给开发人员要做的工作很简单,就是编写 SQL,然后在服务中采用事务脚本的方式实现业务过程。如果业务过程也用存储过程或者 SQL 实现,则数据模型驱动设计的实现模型就只剩下编写 SQL 了。这些工作甚至 DBA 就可以胜任。

如果对比数据设计模型与数据实现模型,我们发现二者没有非常清晰的界限。设计过程实际上取决于对 ORM 框架的选择。

  • 如果选择 MyBatis,则遵循数据映射器模式,为持久化对象建立 Mapper,并通过 Java 注解或 XML,配置数据表与持久化对象之间的映射及对 SQL 的内嵌;
  • 如果选择 jOOQ,则遵循活动记录模式,利用代码生成器创建具有数据访问能力的持久化对象,采用类型安全的 SQL 编写访问数据的逻辑代码;
  • 如果选择 Spring Data JPA,则是数据映射器与资源库模式的一种结合,通过框架提供的Java注解确保实体(即这里的持久化对象)与数据表的映射,编写资源库(即数据访问对象)对象,并通过继承 CrudRepository 类实现数据库的访问。

一旦选定了框架,其实就开始了编码实现。只需要确定业务过程,就可以创建服务对象,并以过程式的方式实现业务逻辑,若需要访问数据库,就通过数据访问对象来完成查询与持久化的能力。

数据模型驱动设计的过程

显然,在数据模型驱动设计的过程中,设计模型与实现模型皆以分析模型为重要的参考蓝本。整个数据模型驱动设计的重头戏都压在了分析模型上。通过对业务知识的提炼,识别出实体和数据表,并正确地建立数据表之间的关系成为了数据建模最重要的工作。它是数据模型驱动设计的起点。因此,一个典型的数据模型驱动设计过程如下图所示:

71999881.png

你可以说这是没有太多设计含金量的过程,但对于简单的业务系统而言,无疑这是简单高效的设计方法。除了数据库性能优化与数据库设计范式之外,它对团队开发人员几乎没有技术门槛,只需掌握三个技能:一门语言的基本语法和编程技巧、一个 ORM 框架的使用方法及基本的 SQL 编写能力——就这三板斧,足矣!这也正是为何数据模型驱动设计能够大行其道的主要原因,无他,门槛低而已。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1435185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法与数据结构】583、72、LeetCode两个字符串的删除操作+编辑距离

文章目录 一、583、两个字符串的删除操作二、72、编辑距离三、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、583、两个字符串的删除操作 思路分析:本题的思路和115、不同的子序列差不多,只是变成…

【RT-DETR有效改进】可视化热力图 | 支持自定义模型、置信度选择等功能(论文必备)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的机制是的是RT-DETR可视化热力图功能,热力图作为我们论文当中的必备一环,可以展示出我们呈现机制的有效性,同时支持视频讲解,本文的内容是根据检测头的输出内容,然后来绘图。 在开始之前…

本地部署TeamCity打包发布GitLab管理的.NET Framework 4.5.2的web项目

本地部署TeamCity 本地部署TeamCity打包发布GitLab管理的.NET Framework 4.5.2的web项目部署环境配置 TeamCity 服务器 URLTeamCity 上 GitLab 的相关配置GitLab 链接配置SSH 配置项目构建配置创建项目配置构建步骤构建触发器结语本地部署TeamCity打包发布GitLab管理的.NET Fra…

【BIAI】Lecture 13 - Language processing

Language processing 专业术语 Aphasia 失语症 fMRI 功能性磁共振成像 auditory cortex 听觉皮层 motor cortex 运动皮层 primary visual cortex 初级视觉皮层 permotor cortex 前运动皮层 课程概要 What is language 语言是一种用词汇按照语法规则组合来表示和交流信息的系统…

【教学类-46-05】吉祥字门贴5.0(华光彩云_CNKI 文本框 空心字涂色 ,繁简都可以,建议简体)

作品展示 背景需求: 1、制作了空心字的第1款 华光通心圆_CNKI ,发现它不能识别某些简体字,但可以识别他们的繁体字(繁体为准) 【教学类-46-01】吉祥字门贴1.0(华光通心圆_CNKI 文本框 空心字涂色&#xf…

nginx+flask+Gunicorn反代理服务拿不到真实IP的解决

背景 本人在宝塔linux环境,要部署flask的简单后端并且用Ngnix反代理,用Gunicorn框架部署。(o(╥﹏╥)o中间磕磕绊绊总算部署上去了,需要了解Gunicorn怎么部署的朋友,评论区留言,我加补一篇介绍)…

CentOS 8 安装配置 Hadoop3.3.6 伪分布式安装方式(适用于开发和调试)

1.配置服务器ssh免密登录,否则后面启动会报错:尝试通过SSH连接到主机出现认证错误的提示 配置服务器ssh免密登录: 1.生成SSH密钥对(如果尚未生成): 执行下面的命令生成密钥对,一直回车即可 ssh…

爬虫实战--爬取简单文字图片并保存到mongodb数据库

文章目录 前言发现宝藏 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们…

七、类与对象

文章目录 类与对象1.1 自定义类1.2 第一个类1.3 private变量1.4 变量默认值1.5 构造方法1.6 类和对象的生命周期 类与对象 本文为书籍《Java编程的逻辑》1和《剑指Java:核心原理与应用实践》2阅读笔记 将客观世界中存在的一切可以描述的事物称为对象(实…

浏览器提示ERR_SSL_KEY_USAGE_INCOMPATIBLE解决

ERR_SSL_KEY_USAGE_INCOMPATIBLE报错原因 ERR_SSL_KEY_USAGE_INCOMPATIBLE 错误通常发生在使用 SSL/TLS 连接时,指的是客户端和服务器之间进行安全通信尝试失败,原因是证书中的密钥用途(Key Usage)或扩展密钥用途(Extended Key Usage, EKU)与正在尝试的操作不兼容。这意味…

性能评测|虚拟化和裸金属 K8s 哪个性能更好?

本文重点 整体而言,SKS(虚拟机 Kubernetes)可以达到裸金属 Kubernetes 性能的 82% – 96%,满足绝大部分场景下生产容器应用的性能需求。更多虚拟化与裸金属 Kubernetes 架构、特性、适用场景与性能对比,欢迎阅读文末电…

【算法】枚举——蓝桥杯、日期统计、特殊日期(位数之和)、2023、特殊日期(倍数)、跑步锻炼

文章目录 蓝桥杯日期统计特殊日期(位数之和)2023特殊日期(倍数)跑步锻炼 蓝桥杯 日期统计 日期统计 如果暴力枚举100个数的八次循环那就是1016次运算,时间复杂度太高了,好在前四次的2023是确定的&#xf…

Mybatis中的sql-xml延迟加载机制

Mybatis中的sql-xml延迟加载机制 hi,我是阿昌,今天记录一下关于Mybatis中的sql-xml延迟加载机制 一、前言 首先mybatis技术本身就不多介绍,说延迟加载机制之前,那要先知道2个概念: 主查询对象关联对象 假设咱们现…

人工智能福利站,初识人工智能,图神经网络学习,第二课

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…

UML之在Markdown中使用Mermaid绘制类图

1.UML概述 UML(Unified modeling language UML)统一建模语言,是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路。 类图是描述类与类之间的关系的,是UML图中最核心的。类图的是用于…

SpringBoot实战第三天

今天主要完成了: 新增棋子分类 棋子分类列表 获取棋子分类详情 更新棋子分类 更新棋子分类和添加棋子分类_分组校验 新增棋子 新增棋子参数校验 棋子分类列表查询(条件分页) 先给出分类实体类 Data public class Category {private Integer id;//主键IDNot…

mysql 批量查询取每一组最新一条数据

AI回答 需求 根据车牌号查询最新的一条交车记录的‘合同号’ ,与上面需要类似,这里只需要查询‘合同号’这个字段 方式1 直接把需要查询的字段加上contract_no,直接查,不用子查询 SELECT number_plate,id,contract_no, MAX( …

❤ React18 环境搭建项目与运行(地址已经放Gitee开源)

❤ React项目搭建与运行 环境介绍 node v20.11.0 react 18.2 react-dom 18.2.0一、React环境搭建 第一种普通cra搭建 1、检查本地环境 node版本 18.17.0 检查node和npm环境 node -v npm -v 2、安装yarn npm install -g yarn yarn --version 3、创建一个新的React项目…

SSRF漏洞给云服务元数据带来的安全威胁

文章目录 前言元数据服务威胁1.1 Metadata元数据1.2 RAM资源管理角色1.3 STS 临时凭据利用1.4 CF云环境利用框架1.5 元数据安全性增强 TerraformGoat2.1 永久性AccessKey2.2 SSRF靶场环境搭建2.3 腾讯云CVM配角色2.4 接管腾讯云控制台 SSRF组合拳案例3.1 上传图片功能SSRF3.2 文…

vue3-内置组件-Transition

基于状态变化的过渡和动画(常用) 建议多看几遍~~。然后动手去写写,学编程只有多动手才能有感觉。 内置组件: 它在任意别的组件中都可以被使用,无需注册。 Vue 提供了两个内置组件,可以帮助你制作基于状态变化的过渡和动…