Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔
Posted Dark And Grey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔相关的知识,希望对你有一定的参考价值。
文章目录
- 前言
- 1.MyBatis 是什么?
- 为什么要学习 MyBatis
- 怎么学 MyBatis?
- 1、创建 MyBatis 项目
- 使用 MyBatis 的操作模式 操作数据库
- MyBatis 执行过程
- Spring Boot的单元测试 - 穿插内容
- 2、单元测试有哪些好处?
- 3.Spring Boot 单元测试使用
- 拓展:“小鸟” - 插件 MyBatisX
- 增、删、该操作
- 在不修改数据库中数据的情况下,完成单元测试 - 穿插
- 查询操作
- 复杂情况:动态SQL使⽤
前言
经过前⾯的学习咱们 Spring 系列的基本操作已经实现的差不多了,接下来,咱们来学习更重要的知识,将前端传递的数据存储起来,或者查询数据库⾥⾯的数据。
1.MyBatis 是什么?
MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。
MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。
Mybatis官⽹
针对 MyBatis 是⼀款优秀的持久层框架 进行分析和补充。MyBatis,也是一个 ORM 框架。
ORM(Object Relational Mapping),即对象关系映射。
在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象的互相转换:
1、 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL
2、将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
数据库表(table)>>> 类(class)
记录(record,⾏数据)>>> 对象(object)
字段(field) >>> 对象的属性(attribute)
⼀般的 ORM 框架,会将数据库模型的每张表都映射为⼀个 Java 类。
也就是说使⽤ MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间的转换。
即:MyBatis 可以称为是一座“桥梁”。
它的作用就是:将 数据库 和 程序,映射起来。
映射起来之后,就可以做一系列的操作了。
比如:
查询,由于我们将 数据库 与 程序映射起来了,直接就把整个数据表映射到一个类里。
查询的结果,就是一个集合,存储的是类的对象(插叙到的一行行记录),那数据也就查询到了。
保存,还是一样的,我们已经将 数据库 与 程序 映射起来了,把表里面的数据,搞到对象里面了。那我们调用对象的某个方法,是不是就可以直接对象的成员直接保存到 mysql 里面了呢!
MySQL 和 MyBatis,是不一样的。
MySQL,提供了一个 数据存取(数据管理) 的软件。
而 MyBatis 是一个“中间桥梁”,用于连接 程序 和 数据库,建立关系映射的,进行 数据操作 的中间层(持久层)。总的来说:
MyBatis 的定义:MyBatis 是一个优秀的 ORM(对象关系映射)持久层框架。
其作用:实现 程序 和 数据库 之间的数据交互。PS:
ORM 框架,并不是只有 MyBatis 一家!
只是说 MyBatis 在国内使用的标胶广泛,大概占据中国市场的90%以上。
国外用的最多的是Hibernate。
至于其中的原因,MyBatis 和 Hibernate 之间的区别等等。。。
包括 在 Hibernate 之后,又有一个 Spring JPA,与其又有和区别?
等 MyBatis 讲完之后,再给你们讲。
(前提是我还记得,没写你们就自己百度吧)MyBatis ⽀持⾃定义 SQL
自定义SQL,包含的范围就很广了。
数据库中的 “CURD(增删查改)”语句,都是可以实现的。
自定义SQL嘛,我们想写什么SQL,就写什么SQL。
由此,不难看出 MyBatis 一个 最大的特点:灵活!
这也是为什么 MyBatis 在国内能够流行的重要原因!!!
其背后的原因,就是国内用户的需求实在是太奇葩了,参差不齐!!
举个生活周围的例子:
几乎所有大学,都会有 计算机专业。
但是!有哪个学校是有 关于 互联网产品的专业?没有!!!
大学不会教,外面培训班又少。
大部分都是 考研的培训班,再其次就是关于 计算机 的培训。
计算机的发展,还是比较成熟的。
但是呢!关于 产品经理 和 产品 的 培训,基本上做这个培训的机构。
反正我是没见过。
原因,就是因为它的市场占有率不高,看不到利益的苗头。
自然也就不会与人去做这件事。
这么说吧:在有些公司,根本就没有产品经理,这个职位。
因此,我们以后所遇到的产品经理,大部分都是只长了一张嘴,会提需要,但是不知道这个需求实现起来,有多复杂!
因为没有培训过,再加上现在的产品经理,大部分都是不懂技术的,
因此,他们提出的需求,千奇百怪。
于是就有了 手机壳的那个段子,完全就是扯犊子。
一个软件,一个硬件,八竿子打不着的两个东西。
因此,MyBatis 灵活性 的作用,就体现出来了。
就是为了 适应 各种需求。
国外,对于 技术 和 产品 已经流程化了,都是经过培训的。
毕竟计算机,外国才是起源地嘛,发展的快,也是很容易理解的。
发展倒极致,就是稳定了。存储过程
我之前将的 SQL,不管是多玛复杂的SQL,我们都是一行SQL解决。
因为 SQL中,并没有特别复杂的业务,像 for循环,if判断。。。这些都没有。
就是一个 很平滑,单一维度 的 SQL 操作,这是针对于 普通 SQL。
但是!存储过程,是SQL中的方法,它是由一大堆 SQL 的组成的。
这个组成里面,它是有循环的,判断的,分支的,有变量传递的。
这个就叫做存储过程,也就是将 SQL 方法化。
反过来理解:
SQL 方法化 的过程所产生的东西,就叫做存储的过程 。
以后,我们工作了之后,别人给我们一存储过程,里面就是密密麻麻的SQL语句。
还有 if 判断,for循环,设置变量的值…
然后,入参,出参,反正就是很大一串的SQL语句。
少则 几十行,多则 上千行。
那为什么我们程序员不会这个存储过程呢?
这其实和 存储过程 的 特性相关的。
虽然 存储过程 能够实现复杂的业务,但是!这只是 将业务 从 程序方 移动到了 SQL 方。
这种情况下,公司对 程序员的要求 就会非常高!!!
试想一下:公司给一个 存储过程,一个几百行的 SQL语句,你估计眼睛都花了。
你能看得懂,才有鬼。。。
但是 总得有人来做吧,这就诞生一个特殊的职业 DBA。
DBA:Database Administrator —— 数据库管理员,又称数据库开发工程师 。
他的SQL是很牛的,他不用写程序的。
每天都是在捣鼓 SQL 语句的,只玩数据库的,玩数据的。
对于 大部分程序员来说:根本就搞不懂 存储过程 ,这么复杂的东西!
而且,存储过程中有一个特别特别难用的东西!
我们在敲一个很复杂的 java 代码的时候,可以通过 debug 可以一步一步去调试,进入类,方法,属性中,来观察运行时的状态。从而能够帮助我们排查程序中存在的错误。也及时 程序 是能够调试的。
但是 存储过程 是不能调式的。
也就是说:一个存储过程,有这几百行的SQL语句,要我们去写。
而且,出现了错误,只能通过肉眼去排查错误。【不支持调试】
我敢说:百分之90的程序员,都做不到这一点。
这是属于 真正的天才,才能胜任的工作。
但是!也请放心!
公司也不可能让我们程序员去做这件事的。
一般都是外聘的专业人员来操作的。
存储过程,用的最多的就是 医院。
医院需要对每天,每月,每年,进行数据(收入,考勤。。。)汇总(各种报表)。
总之涉及到数据,非常多。
这就需要从各个数据表中 抽取数据。
此时 简单的SQL语句,就搞不定了。
这个时候,才会用到存储过程。
由于存储过程 的难度,非常大!
对人要求很高,随之而来的就是高额的工资。
大概是我们程序员工资的 1.5 倍以上。
即:招一个程序员约定1万工资,那 DBA 的工资,至少是 1w5 以上,要不然你找不到人的。高级映射
高级映射,除了可以实现 数据表 和 程序里面的对象 映射之外,还可以实现 一对一的多表映射 和 一对多的映射。
比如: CSDN
每一篇博文,都有它的作者。
博文 与 作者 的关系,就是一对一的关系。
此时,使用 MyBatis 就可以在进行查询的时候,进行 连表查询,并且将 查询到的数据结果,映射到 我的某一个 文章对象里面。
再来,一个作者,他可以发很多篇博文。
站在这个角度,作者 与 他发布的博文,成 一对多的关系。
这种情况,使用 MyBatis 也可以实现这个任务。
MyBatis 可以直接去查询数据库里面的数据,然后,将这些 数据 赋值 给 UserInfo。
这个 UserInfo 里面是有一个属性的(list article - 文章列表)。
就是用来记录这个作者创作的作品。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。
以往,我们在进行 JDBC 编程的时候,需要获取数据源对象(DataSource),然后设置三个属性 URL(数据源路径),用户名(默认是 root),密码(MySQL的登录密码)。
在设置完这三项之后,然后才能与数据连接,进行一系列的操作。
另外在获取 结果集的时候,我们需要使用到一个 类(ResultSet)的对象,来接收数据库返回的结果集,还需要通过 迭代器的方式,才能进行后续的打印。
使用了 MyBatis ,上鞋这些就都不需要了。
它会自动帮我们实现映射,
我们只需要写 SQL 语句(不要写错),写完之后,它会把这个 SQL语句 执行,将 查询到的结果(表数据),直接全部映射到对象里面。
也就是说: JDBC 的前置操作的代码,我们一行都不需要写。
MyBatis 直接全包了,你直接用就行。
特别爽!MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
MyBatis 在实现的时候,它有两种实现方式:
1、通过 xml 来实现数据的操作,数据操作支持所有的类型。
这是在 MyBatis 3.1 版本之前,主流的一个操作方式。
使用 xml 的形式,来实现 对数据库进行 “CURD” 操作。
但是呢!在3.1 版本之后,MyBatis 有了新的选择。
也就是 第二种方式(注解方式)。
但是目前主流还是使用的 xml 形式。
为什么呢?
我们不说 MyBatis 使用起来,非常灵活!
灵活是需要付出代价的!
代价,就是我们要去写 SQL语句。
你试想一下:我们在注解中写一个 SQL语句,是不是很别扭?
代码没多少,注解倒是非常长。
所以,MyBatis 在 3.1版本之后, 提供了 注解 这个新的操作数据方式。
它也没有用,因为不好用。
注解的方式,用来实现简单 SQL 操作,还是可以的。
但是!一旦SQL语句复杂了一点,你在使用的时候,就会特别别扭。
注解 比 代码,还有长。。。
而 xml 写SQL语句比较灵活,也不会感觉到别扭,好用!
所以,本文也是 基于 xml 来实现 对数据库 进行操作的。
为什么要学习 MyBatis
对于后端开发来说,程序是由以下两个重要的部分组成的
1、后端程序
2、数据库
⽽这两个重要的组成部分要通讯,就要依靠数据库连接⼯具,那数据库连接⼯具有哪些?
⽐如之前我们学习的 JDBC,还有今天我们将要介绍的 MyBatis,那已经有了 JDBC 了,为什么还要学习 MyBatis?这是因为 JDBC 的操作太繁琐了,我们回顾⼀下 JDBC 的操作流程:
1、 创建数据库连接池 DataSource
2、 通过 DataSource 获取数据库连接 Connection
3、 编写要执⾏带 ? 占位符的 SQL 语句
4、 通过 Connection 及 SQL 创建操作命令对象 Statement
5、 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
6、 使⽤ Statement 执⾏ SQL 语句
7、 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
8、 处理结果集
9、 释放资源
实例代码 - insert 操作 - 截取自 我自己的文章内容。
从上述代码和操作流程可以看出,对于 JDBC 来说,整个操作⾮常的繁琐,我们不但要拼接每⼀个参数,⽽且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接等,⽽所有的这些操作步骤都需要在每个⽅法中重复书写。于是我们就想,那有没有⼀种⽅法,可以更简单、更⽅便的操作数据库呢?
答案是肯定的,这就是我们要学习 MyBatis 的真正原因,它可以帮助我们更⽅便、更快速的操作数据 库。
之前使用 jdbc 需要进行九步操作,现在使用了 MyBatis,就写一个方法,一个 SQL就搞定了。 像什么手动释放资源,处理结果集,都不用我们去做了。MyBatis “保姆级” 助手。
怎么学 MyBatis?
本文重点分为两个部分:
1、配置 MyBatis 开发环境(创建一个 SSM 项目)
2、使用 MyBatis 模式和语法 操作数据库
1、创建 MyBatis 项目
准备工作:创建数据库 和 数据表
下面我们会创建一个关于 博客 的 数据库 mycnblog
并且在 mycnblog 数据库中创建三张表。
代码给你们了,戴氏!里面暗藏 “杀机”。
会导致 产生一个 BUG,不然有解决的方法,
先就这么弄。不过有一点需要注意!
在 文章表中的 content字段,它的类型是 text。
text 能够表示文本内容有限,在实际情况中,一般是使用 longtext。
另外, createtime 字段,我们使用了一个 now 方法,这个 now 方法,需要 MySQL 的版本,在5.5以上。
不过应该问题不大,毕竟我们 与 jdk1.8 配套的数据库版本,是 5.7版本的。
你仔细看下面创建 SQL,无论是创建 数据库,还是数据表,我都设置了 字符集为 utf8。
确保一定是支持中文的。
这样做的好处,就是:哪怕你们没有修改数据库的配置,创建出来的表,仍是是支持中文的。
还有一个小细节:在添加一个用户信息的SQL语句中,我们的密码是明文存储的。
这样去写,势必会遭到 面试官的吐槽。
即使你使用了 md5 进行加密,其实也没有多大作用。
如果只是一个 md5,其实我们可以通过 “彩虹表” 进行穷举,来获取你的密码。(注意!这不是解密,是穷举你密码的可能性)
有人肯恩就会想法:
密码 在一次 md5 的情况下,能够通过 彩虹 表 来穷举 获取密码。
那我们 对 密码 md5 两次,甚至更多呢?
那 彩虹表是不是就破解不了了??
你都能想得到,别人黑客就想不到吗??
别说两次,就算你 3次,4次,甚至是五次,人家 应对方法的。
而且,无论你md5加密几次,其实就是累加的效果,对于黑客来说无非就是多 穷举几次而已。
最靠谱的方式,就是有随机数的,有变量的。
这样做更靠谱!
因为是随机生成的嘛,没有规律可言!
想要获取密码,就非常难!
几乎是不可能的。
-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8;
-- 使⽤数据数据
use mycnblog;
-- 创建表[⽤户表]
drop table if exists userinfo;
create table userinfo(
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime datetime default now(),
updatetime datetime default now(),
`state` int default 1
);
-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime datetime default now(),
updatetime datetime default now(),
uid int not null,
rcount int not null default 1,
`state` int default 1
);
-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
vid int primary key,
`title` varchar(250),
`url` varchar(1000),
createtime datetime default now(),
updatetime datetime default now(),
uid int
);
-- 添加⼀个⽤户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`,
`createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48',
1);
-- ⽂章添加测试数据
insert into articleinfo(title,content,uid)
values('Java','Java正⽂',1);
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java
title','http://www.baidu.com',1);
打开你们本地的MySQL,将上述SQL,复制粘贴到 MySQL中。
PS: 建议先拷贝到 一个文本文件中,然后再拷贝到 MySQL中。
因为你如果直接拷贝上面的内容,SQL就会挤成一坨。
也就是说不带有格式的。
你把上面代码先放在笔记本中,再粘贴到MySQL中。
不但没有挤在一起,而且SQL全部执行了,只有最后一句SQL没有执行。
直接回车,就全部OK了。
我们下面来看看数据,有没有插入成功
1.1、添加 MyBatis 相关依赖
眼尖的朋友,会发现我使用了 “相关” ,这个形容词。
没错,我们要想使用 MyBatis,光引入 MyBatis 依赖,是不够的。
我们需要引入一个依赖(关于数据库的)。这里就会涉及到两个场景:
1、项目创建的时候,引入 MyBatis 相关依赖
2、老项目,添加 MyBatis
1、新建一个 MyBatis 项目
然后,就是将 无用的文件,删除掉。
2、在老项目中引入 MyBatis 相关依赖
这个讲了很多次,使用 Edit Starter 插件 添加。
1.2、配置数据库连接字符串
不要立即启动项目!!!!
如果立即启动项目,就会报错。
指针对 社区版 idea,专业版会帮助我们自动生成关于 数据库的 配置信息。社区版:
这是因为 没有配置 关于 数据库的数据源的 URL
专业版:
直接就给我们配置好了。
现在我把的配置文件删除掉,重新创建一个配置文件,与社区版保持一致,我们来重新编写配置信息。
我们需要配置 4 项:
此时,我们再启动项目,就不会报错了。
1.3、配置 MyBatis 保存的 xml 的目录
我们前面说过 MyBatis 有两种 操作方法:
1、使用 xml 的形式 实现呢
2、 注解(MyBatis 3.1版本之后,开始提供)
但是!
注解的方式,并不好用。
因此,我们主要还是关注 xml 形式,是如何操作 数据库。
思考一下:
xml 是一个 资源文件,对不对?
那么,xml 文件,还是放在 resource 目录下。
还有一个问题:
放在 resource 哪个 目录底下。需要注意的是:一般是不会将其放在 resource 根目录底下,与配置文件处于同一级目录。
因为到时候,配置文件,非常多!
此时,你放进去,不就是添乱嘛!!!
通常我们都是在resource 目录下,创建一个子目录,用来存放的。
使用 MyBatis 的操作模式 操作数据库
MyBatis 的操作模式
MyBatis 的 操作模式,包含两个部分:
1、Interface(方法定义)
2、xxx.xml注意!这里是接口,不是类。
这个interface 中 会加一个注解,它是来自于mybatis里面的注解 Mapper。
加了这个注解之后,表示我们当前的这个 mybatis 类 所的事情,就是 实现 对象的映射。
这个时候,帮我们的方法名字 定义到 interface 里面。
我们 interface 里面的方法,是不能有实现的,是一个抽象方法。
思考一下:
假设,我们要根据用户ID 去查询一个用户信息。
那我们定义一个方法名有什么用?又没有具体实现,怎么可能会实现查询功能??
答案显而易见是不行的!!!
'这个时候,我们就需要另一个东西:xml 文件
mybatis 有点奇怪,感觉就像是 “怕脑门” 想出来的方法 。
就是 要想操作数据库,必须得有两个文件。
第一个,它是Java中的 一个普通接口,在接口中,定义方法名称。
定义方法名称之后,就该实现方法了。
但是接口中方法不能有实体,需要通过一个注解来进行映射方法,映射一个 xml 文件中。
当然,在xml文件中,也需要表明它是那个方法的映射。
这就是第二个文件 xml。
根据我们前面讲的映射:就是 把业务代码 转换成 SQL 语句。
也就是说我们 定义在接口中的方法,是为了声明该方法 对数据 进行 何种操作。
具体的实现 已经通过某种映射关系,映射到 xml 文件中,
我们需要在 xml 文件中,编写 对应功能的 SQL 语句,就可以了。
有的人可能会疑问:
我们可不可以将 SQL 语句 写在代码中,就像 jdbc 编程 一样。
答案:可以,但是!SQL 只能是 String 类型的,如果SQL写错,它是不会报错的。
这就很容易翻车。
所以,mybatis 的设计师 思考一会,这样的话要不直接把 SQL 写在 xml 里面?
于是一拍大腿,就这么决定了。
在xml里面,只需要配置 我们要是实现的 interface 是谁,我要实现的 SQL 是谁。
OK ,这样一配置就完了。
这两个合在一起,最终生成 mybatis 中能执行的SQL。
通过这个SQL语句,去操作数据库。
将 操作数据库得到的结果,返回给 服务层。
服务层,再返回给 controller(控制层)。
控制层,再把结果交给用户。
这样 就完成了 一次交互。所以,我们讲 mybatis 的 操作模式,就是在讲下图中的两个文件。
这两个配合起来,就能生成 数据库可以执行的SQL语句,并且执行 SQL,操作数据库。
并将 结果 映射到程序的对象中。
第⼀个MyBatis查询:实现一个根据用户id来查询用户信息的操作
我们要实现一个 根据 用户id 来查询用户信息的操作。
前面我们在准备工作中,就是已经给 userinfo 表中插入了一个数据。
下面,我们就来完成这样的一个功能。
1、定义接口
2、创建 xml,实现上面的接口
xml 文件,不能随便创建。
我们在配置文件中,已经指定了 xml 文件存储路径。
并且,命名规则也指定了。
我们必须按照规则来。
至于 xml 文件的配置内容,直接把下面的内容,拷贝到里面去。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
</mapper>
相信很多朋友,都会发现 mapper标签中的 namespace 属性,缺少value值。
namespace 的值,是需要我们手动去填写的。
填写的内容:是需要时实现的接口位置 >> 包名 + 接口名称。
接下来,就是在 xml 文件中,实现 UserInfoMapper 接口 中的 方法。
关于获取方法参数,使用的 $ 和 # 的区别,后面会详细讲。
&enso;
好,关于 MyBatis 的操作,就都完成了。
下面,我们就可以来验收成果了。
运行结果展示
我们在 service 包底下创建一个 UserInfoService 类。
在里面 写一个方法, 去 调用 UserInfoMapper 中的方法。
然后,在 controller 包下,也去创建这样的一个类,去调用 UserInfoService 中的方法。
此时,我们将项目启动起来。
注意!有的人可能会在这一步出现问题
我被坑的头皮发麻。
第一次遇见版本不匹配,引起的错误。
看异常信息检查不出错误。
出现这个问题的原因是:我们添加的 MyBatis r的版本太高了,而我们使用的 Spring Boot 版本太低了(阿里云提供的)。导致的版本不兼容。
因此 URL 不能像正常情况下,那样去配置。
应该这样去配置
更简单解决方法的是:使用官方 提供的Spring Boot 框架,选择次新的。
我使用的是 阿里云,所以 版本很低,我是用的版本是 2.3.7。
所以,才会出现上述情况。
MyBatis 执行过程
在这里,我在补充一点。
我们在写 mybatis 代码的时候,无非就是两个操作:1、创建接口,定义方法;2、在写满了文件中编写SQL。
整个 mybatis 操作 完成了。
这里有一个比较麻烦的地方:
就是在我们写完功能之后,我们要进行测试的话,成本很高!mapper的内容写完,我们还需要写 service,写 controller,还没完!
我们还需要打开 浏览器方法(或者利用postman来模拟访问)。
虽然整个流程,非常有序,一环接一环。
但是!这会让人感觉很拖!
给人的感觉就是:代码被强行 “ 拉长 ” 了。那有没有什么方法,能让我们写 mapper 内容之后,直接可以进行测试呢?
这就是下面,我要讲的东西:Spring Boot的单元测试
Spring Boot的单元测试 - 穿插内容
讲这个,是为了后面讲解 Mybatis 的内容。
1.什么是单元测试?
单元测试(unit testing),是指对软件(项目)中的最⼩可测试单元进⾏检查和验证的过程就叫单元测试。
单元测试是开发者编写的⼀⼩段代码,⽤于检验被测代码的⼀个很⼩的、很明确的(代码)功能是否正确。
执⾏单元测试就是为了证明某段代码的执⾏结果是否符合我们的预期。如果测试结果符合我们的预期,称之为测试通过,否则就是测试未通过(或者叫测试失败)。
最小可测试单元:方法
每一个方法都代表一个相应的功能。
那我们测试的最小单元,对于 Spring Boot 来说,就是一个方法。
OK,你写一个方法,我测一个方法。
测试方法,就是测试一个单元。
方法,是不可以再被分割的!
你不可能说: 我们去测试 方法中的某一段程序,或者说测试某一个属性。
因为,这叫做 调试。
调试 和 测试单元,是两码事!!!!
但是!有的朋友可能会说:
方法中,经常会调用另一个方法,来“辅助”自身的运行。
那这种怎么说?
如果方法中还有方法,这个时候,单元测试就需要分为多个了。
首先是这个方法中所有依赖的方法,我们可以对这里面所有的方法,做一个单元测试。
最后,再回到本身,对本身的方法进行单元测试。
2、单元测试有哪些好处?
1、单元测试不用启动 Tomcat
对于这一点,不好说。这个说法,要分角度来看。
从自身的角度来看:我们确实没有启动 Tomcat,但是 Spring Boot 自动启动了 Tomcat。
因为 Spring Boot 内置了 Tomcat。
其实 Spring Boot 除了支持 Tomcat,还支持其它的Web容器。2、如果中途修改了代码,在项目打包的时候会发现错误,因为打包的时候会自动执行单元测试,单元测试错误就会发现。
这一点最重要!
3、单元测试,最大的一个好处 :
让我们非常方便,非常直观,也非常直接的,在写完一个功能之后,立马就能知道这个功能是否是正确的!
这也是我们学习单元测试的初衷,就是为了降低 测试 mybatis 功能的成本。
4、不使用单元测试的时候,它是会 “ 污染 ” 本地的数据库的!
就是比如说:
我们实现了一个 添加 功能,我们要去测这个添加功能。
这就需要正儿八经的去进行添加操作的。
这就会对本地数据库中的数据,发送变动。
这就是 “污染”!
然而,如果使用了 单元测试 来测试功能,.
测试单元,就能保证在 测试完功能之后,对于数据库中的数据没有任何影响!这个牵扯到了 事务的回滚机制。
这是 我在讲 MySQL是如何保证事务的原子性 的 时候,提到过的 事务回滚机制。
有兴趣,就自己去看,目录给你标出来了。
单元测试,也是通过利用 数据库的回滚机制 来 避免对 数据产生 “ 污染 ” 。
也就是说:我们在执行单元测试之前,MySql 为其创建了一个事务。
【MySQL 默认情况下,是处于开启事务的状态,也就说开启了事务的自动提交】
然后,开始执行单元测试,对数据库中的数据进行操作。
在验证完 单元的功能没有问题之后,就会进行事务的回滚操作。
还原到 还没有测试的情况。【将数据还原到初始状态】
3.Spring Boot 单元测试使用
Spring Boot 项⽬创建时会默认单元测试框架 spring-boot-starter-test,⽽这个单元测试框架主要是依靠另⼀个著名的测试框架 JUnit 实现的,打开 pom.xml 就可以看到,以下信息是 Spring Boot 项⽬创建是⾃动添加的:
PS:我用来演示效果的项目,是我一步一步带着大家创建的。
所以,作假含量极低。我可没有偷偷添加这个依赖!
都是 Spring Boot 干的!!!雨我无瓜!
这里有一个细节:
&enspp;
单元测试的实现步骤
1.⽣成单元测试类
这个时候,此⽅法是不能调⽤到任何单元测试的⽅法的.
此类只⽣成了单元测试的框架类,具体的业务代码要⾃⼰填充。
2 添加单元测试代码
1.添加 Spring Boot 框架测试注解:@SpringBootTest
至于为什么还需要加一个 测试注解,是因为 我们生成测试类,是一个普通的类。
但是!测试接口,它是一个普通的接口吗?
因此,我们需要在测试类上 声明它要测试的方法,是运行在 Spring Boot 容器当中的。
所以,@SpringBootTest 注解,就是起着这样的一个声明作用。
表示当前这个类中 测试方法(测试单元) 是运行在 Spring Boot 中的。
2.添加单元测试业务逻辑
3、开启测试
虽然,从打印的结果来看,功能是没有的。
而且,左边那几个 绿色勾勾,代表测试通过。
但是! 我们是使用 的 sout 语句,来对查询结果进行输出。
这并不是 我们 单元测试的效果!!!!
单元测试的效果应该是 单元测试中的断言!!!断言:
就是说:以什么为标准,
通过这个标准来衡量 测试是否通过。
比如,如果 断言的结果为 true,就表示 单元测试 通过了。
反之,断言的结果为 false,就表示 单元测试 不通过。
并且!断言之后的代码,是不再执行的!!!所以。还没有完。
单元测试,还有一部分是关于 断言 的 内容。
我们是需要知道的。
4、简单的断⾔说明
由 Assertions 类提供的,注意!这个类是 JUnit 提供的
下面,来跟着我看一下,如何使用断言,来判断单元测试是否通过!
这就是断言的魅力,一旦出错。
如果测试失败,它的报错信息会非常非常的详细!
后面,我们实现 增,删,该2的时候,就不需要 浏览器 和 postman了。
直接使用断言,来测试即可。
这里做一个小拓展:
为什么有些人的 科学版 idea, 在进行 与 @Mapper 相关的属性注入,使用 @Autowired 来注入,为什么会报错?
拓展:“小鸟” - 插件 MyBatisX
它能够帮助我们快速切换 接口 和 xml。
让我们操作 MyBatus 更舒服。
而且,还能帮我们自动去生成代码。
增、删、该操作
接下来,我们来实现⼀下⽤户的增加、删除和修改的操作,对应使⽤ MyBatis 的标签如下:
< insert >标签:插⼊以上是关于Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔的主要内容,如果未能解决你的问题,请参考以下文章
MyBatis案例 | 使用映射配置文件实现CRUD操作——动态SQL优化条件查询