Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

前言

经过前⾯的学习咱们 Spring 系列的基本操作已经实现的差不多了接下来咱们来学习更重要的知识将前端传递的数据存储起来或者查询数据库⾥⾯的数据。


1.MyBatis 是什么

MyBatis 是⼀款优秀的持久层框架它⽀持⾃定义 SQL、存储过程以及⾼级映射。
MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJOPlain Old Java Objects普通⽼式 Java 对象为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具也就是更简单的操作和读取数据库⼯具。
Mybatis官⽹

针对 MyBatis 是⼀款优秀的持久层框架 进行分析和补充。

MyBatis也是一个 ORM 框架。
ORMObject 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。
DBADatabase 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 POJOPlain 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 >标签插⼊语句
< update >标签修改语句
< delete >标签删除语句

接口的定义还是一样的写法。
写法的差异主要就体现在 xml 中 的 自定义 SQL 语句 上。


MyBatis 修改操作

我们先给 userinfo表插入一条记录。
在这里插入图片描述
下面实现 改操作。
在这里插入图片描述
下面我们来拓展几个细节
1、方法参数 使用 @Param 注解之后原先参数的名称不能再使用。
在这里插入图片描述
得出结论
@Param 注解 和 @RequestParam 注解起着相同的作用。
方法 参数重命名。一旦重命名之后原来的名称是不能使用的。

只不过 @Param 注解中的参数是 重命名后的结果。
而 @RequestParam 注解中的参数 是参数原名方法参数是 重命名的结果。

于此同时我们又发现了一个问题。
当我们测试完之后我发现此时数据中的数据被 “污染”了
前面不是说单元测试不会污染 数据库中的数据嘛
下面我们就来实现这个功能。
【免得你们认为我是个老六说我忽悠你们】


在不修改数据库中数据的情况下完成单元测试 - 穿插

方法很贱简单在测试的单元上加上一个注解@Transactional就行了。
@Transactional就是事务的意思。
其作用就是在开始执行测试之前开启一个事务。
这个事务完成的任务就是我们定义的是SQL操作。
在 操作完成之后也就是测试完成之后该事务会进行一个 “ 回滚 ” 操作。
原来的数据是什么样子的现在还是什么样子的。

就是说事务执行的期间确实 “ 污染 ” 了 数据库中的数据
但是在事务执行完成之后事务会通过 “ 回滚 ” 操作将被 操作的数据还原到未修改的状态。

这里需要注意一点
@Transactional 注解原本只是提供一个 自动提交事务的功能。
并不会提供 自动 “ 回滚 ” 功能。
只是说 该 单元测试 所处于的 测试类是被 @SpringBootTest 注解 修饰的。
等于就是说“强行” 给 @Transactional “ 加班 ”
无论 单元测试是否成功都会进行一个 事务的 “ 回滚 ”将数据库的数据还原
在这里插入图片描述
我没有晃点你们吧
只需要在 测试的单元上再加上一个 @Transactional 注解就可以在 “ 不污染 ” 数据库中数据的前提下完成单元测试。

当然这个操作的大前提
是在 测试的单元所在的测试类是被 @SpringBootTest 注解所修饰的。


MyBatis 删除操作

有了 修改操作删除操作实现起来就简单很多了。


1、在 mapper 中的 UserInfoMapper 接口中定义 方法

在这里插入图片描述


2、在xml文件中 编写 SQL语句 的相关代码。

注意只有 select 标签特殊一点需要指定返回类型。
delete 标签 和 update 标签都是一样的。
在这里插入图片描述


单元测试 - 验证功能效果

在这里插入图片描述

有了 修改 和 查询操作的基础这个删除操作就跟玩一样。
很快就能搞定


MyBatis 插入操作

这个插入操作相比前面 “ 删查改 ” 操作要复杂一些。
所以把它放在最后来讲。
操作还是一样的只是插入的值是一个对象在 编写 SQL的时候如何获取对象的属性是一个问题。
还有返回值的处理。


先实现最简单 的 插入操作

返回值返回一个受影响的行数

1、在 mapper 中的 UserInfoMapper 接口中定义 方法

在这里插入图片描述


2、在xml文件中 编写 SQL语句 的相关代码。

在这里插入图片描述


3、进行单元测试

在这里插入图片描述

算了为了防止你们认为我做假。
我 “污染”一条 王五的信息。
在这里插入图片描述


上面最简单的实现方式下面我们来看难一点的实现。

现在我们不想 将 影响的行数作为返回值了。
我要 插入成功的用户信息的ID
虽然实现的步骤没有变化但是想要达到预期的效果还需要做点事。


先来看第二步在xml文件中 编写 SQL语句 的相关代码。

在这里插入图片描述

对了我还扩展一下。
在上述 insert 语句中最好加一个属性keyColumn。
更保险
在这里插入图片描述
useGeneratedKeys
这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键
⽐如像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段默认值false。

keyColumn
设置⽣成键值在表中的列名在某些数据库像 PostgreSQL中当主键列不是表中的第⼀列的时候是必须设置的。如果⽣成列不⽌⼀个可以⽤逗号分隔多个属性名称。

keyProperty
指定能够唯⼀识别对象的属性MyBatis 会使⽤ getGeneratedKeys 的返回值 或 insert 语句的 selectKey ⼦元素设置它的值默认值未设置unset。如果⽣成列不⽌⼀个可以⽤逗号分隔多个属性名称。

简单来说我们加上 keyColumn 的原因就是为了确保获取 对应字段。


再来看一步在 mapper 中的 UserInfoMapper 接口中定义 方法。

返回受影响的行数 和 自增 id
在这里插入图片描述


我们测试一下。

带了这一步我就不给你们演示如何创建 单元测试了。
这都soEeasy的事情了。
另外我直接上代码。
看不懂就返回去看前面的。
在这里插入图片描述
有的人可能会有疑问自增ID是有什么问题吗
其实没问题
这是因为 MySQL 中的 搜索引擎 InnoDB 的机制就是这样设计的。

学到这里就可以将一些 简单的servlet 项目改成 SSM 项目。


查询操作

单表查询

这个就是前面的 第一个 MyBatis 查询 。
它急救室一个单表查询。

单表查询就是字面意思
在一张表中查询数据。

这个我就不重复讲了。
来看下面的重点


参数占位符 #{} 和 ${} 的区别

#{}预编译处理。
${}字符直接替换

预编译处理是指MyBatis 在处理#{}时会将 SQL 中的 #{} 替换为?号使⽤ PreparedStatement 的 set ⽅法来赋值。直接替换
而MyBatis 在处理 ${} 时就是把 ${} 直接替换成变量的值。
 
这里需要普及的一点
MySQL中有两种查询1、叫做及时查询字符直接替换2、预查询预处理
及时查询当了需要执行SQL的时候才会去执行SQL
预查询相对于 及时查询预查询要多出两步既然查询的参数会变那先用一个 号占位符 顶替参数先构造好一个SQL进行预查询看看SQL的格式有没有错误。
随后通过 jdbc 的方式来替换 占位符。这样就能保证SQL的正确性。

你可能觉得这麻烦但是其实预查询是为了提高查询效率的。
举个例子在这里插入图片描述

通过上述的代码只能证明 #{} 和 ${} 对于 查询条件为整形的查询效果是一样至于效率只能意会毕竟我们感知不到。
但是安全性是可以体现的下面我们就来演示一下。
在这里插入图片描述

由此不难得出结论#{}支持所有的数据类型${} 只支持 数值类型
再举个例子来加深对 预编译【 #{} 】和字符串替换【 ${} 】之间的区别 的理解

头等舱和经济舱乘机分离的故事
在坐⻜机的时候头等舱和经济舱的区别是很⼤的如下图所示
在这里插入图片描述
⼀般航空公司的客运机都是头等舱和经济舱分离的头等舱的⼈先登机登机完之后封闭头等舱然后再让经济舱的乘客登机这样的好处是可以避免有人浑⽔摸⻥经济舱的⼈混到头等舱的情况这就相当于预处理可以解决程序中不安全越权处理的问题。

⽽直接替换的情况相当于头等舱和经济舱不分离的情况这样经济舱的乘客在通过安检之后可能越权摸到头等舱如下图所示
在这里插入图片描述
这就是 直接替换【 ${} 】 所带来的缺陷。
就是说 SQL 没有正确访问它应该访问的地方。
这就是 SQL注入的安全问题。

而且由于头等舱的票很贵买的很少。
通常是坐不满的因此上述这种 经济舱的人 做到 头等舱也是常有的 。
最好的方法就是前面说的一下先让头等舱上机上完之后。
关闭头等舱的入口然后经济舱的人开始上机。
这样就不会存在有 “ 误入 ” 的情况了。

有些人的素质是真的低买了低价的票却想着享受高价的服务。
如果不让他如愿它还恶意举报 航空公司。

所以出现这种问题的根本原因就是等级没有分明。
头等舱的门就相当于是一个界限。
将 头等舱 与 经济舱 分离了。

有的人可能会说加一个检票员来检查票据。
这样不也能解决问题嘛。
但是你遇到不讲理的怎么办
它就是要坐
它有一大堆歪理由。。。。
这时候你想把它请出去非常难
容易产生纠纷。
所以不推荐这样去做。

因此正如前面所说在登机的时候就把 人员分开。
让优先级高的线上就不会存在纠纷问题。
同样也很高效。
 
这样就不用做第二次校验也就不会产生纠纷问题。
即使 头等舱的用户来迟了叫一个空乘服务人员专门领他过去就行了。
领进去再把门一关。
经济舱的人还是混不进入的。

也就是说每个人都只经历了一次检验机票就完成了登机。

那么问题来了。
既然 #{} 这么无敌那么${} 是不是就可以滚蛋了

NO
存在即有意义【蚊子除外】
下面我们来看 ${} 的使用场景。
在这里插入图片描述
其实与其说是 ${} 的优点不如说是它的专长
毕竟 这任务#{} 做不了只有它能做

前面不是说
使用 ${} 存在 SQL 注入的问题嘛
现在哪怕是处于 ${} 的主场依然也存在着这个问题
那如何处理呢

注意事项
当不得不使用 ${} 时那么一定要在业务代码中对传递的值进行安全校验
就是说当代码执行到 mapper 这一层就没救了
只能 “ 上战场 ”了。。背水一战。
所以一定要在业务代码中,对数据校验。
Controller 的作用就体现出来了
因为 它就是负责对数据的校验。
结合现在的情况就是对 传递过来的 order 进行 判断非空长度不能为0甚至对内容进行校验是否是 desc 和 asc其中的一个。

结合生活案例
我们在上地铁火车飞机等公共交通工具的时候为什么在我们乘坐之前就开始检查我们的包裹而不是 上车的时候检查包裹。
这我们的 ${} 的校验数据是同一个道理。
为了保证传递的数据的安全性以及正确性。【确认没有违规物品保证乘客的声明安全】


${} 的经典问题SQL注入问题

在这里插入图片描述

由上面的例子相信大家对 SQL注入问题有了一定了解。
SQL注入问题就是在我们没有对 传递数据进行校验的前提下。
当我们处于一些特殊场景的时候可以在不满足获取条件的情况下获取私密信息。
这对用户信息和 财产的安全隐患是非常巨大的
这就是安全漏洞啊

所以请一定一定一定切记在处理一些重要信息的时候如果使用了 ${}请在 Controller 层对数据进行严格校验

我们再来试一下把 $ 改成 # 效果会如何
在这里插入图片描述
由此不难得出结论
使用 #{} 是不存在 安全漏洞滴
是非常nice的。


like 查询 - 特殊情况

前面的问题由于关键字就那么几个。
直接穷举很容易在 Controller 层里面 判断数据的正确性。

但是模糊匹配能穷举吗
很显然是不能的
如果数据有个几百万那我们不得嗝屁
下面演示一下。
在这里插入图片描述
此时问题也就随之而来了
在进行模糊匹配查询的时候不能使用 #{} 否则会报错
而改用 ${} 有穷举不了所有的情况。
无法做到完美验证数据的正确性和安全性。

那么怎么解决这一个问题呢
使用concat拼接方法就可以解决问题了。
在这里插入图片描述


#{} 和 ${} 的区别总结

1、定义不同#{} 预处理而 ${} 是直接替换

2、使用不同#{} 适用于所有类型的参数匹配但 ${} 只适用于数值类型。

3、安全性不同#{} 性能高并且没有安全问题但 $ {} 存在 SQL 注入的安全问题。

4、使用场景不同
当传递的是一个 SQL 关键字 的时候只能 使用 ${} 。
当传递的是一个字段总之就是需要获取到参数类型 与 内容只能使用 #{}。
PS数字类型#{} 和 ${} 都是可以使用的

5、 ${} 不能用于 模糊匹配查询而 #{} 需要搭配 concat 才能在模糊匹配中使用。


多表查询

前置知识

返回类型resultType

这个大家都很熟悉我们已经在前面的示例中使用了很多次。
用于指定 SQL 查询结果 映射的对象类型。
但是这里有一个细节
在这里插入图片描述
除了修改 实体类属性名称还有一个方法使用 下面即将介绍 resultMap。
在这里插入图片描述

返回字典映射 resultMap

resultMap 使用场景

1、字段名称和程序中的属性名不同的情况可以使用 resultMap 配置映射、
这个上面演示过了就不再演示了。

2、一对一和多对多关系可以使用 resultMap 映射并查询数据。


resultType && resultMap 的区别

1、在对象属性名称 与 数据表字段名称相同的情况下
使用 resultType 比 resultMap 更爽

2、在对象属性名称 与 数据表字段名称不同的情况下
使用 resultMap 可以指定 不同名称的 字段与属性 的映射关系。


有了 resultMap 和 resultType 的基础我们下面就可以真正开始进行多表查询的操作了。

在 MyBatis 中支持的多表查询有两种
1、 一对一关系以博客来说一篇博文只能有一个作者文章和作者的关系就是一对一。
2、一对多关系一个作者可以是 多篇博文的作者。都是他写的嘛作者 和 文章是 一对多的关系。


MyBatis 多表查询一对一关系

下面我就来模拟实现一下 一对一的关系。
but在此之前我们需要创建关于文章表的实体类。
我们前面只是创建一个 用户表的实体类。
在这里插入图片描述
在进行查询之前我们先来看一下 articleInfo 表中有几条信息信息的内容是什么这样方便我们后面写代码。

在这里插入图片描述
如果你们的content 出现乱码反正就不是中文。
你就可以参考这篇文章MySQL第二讲在文章的最后讲了如何配置字符集的问题在这里插入图片描述

下面我们去mapper 包中在创建一个 MyBatis 的接口。
实现根据文章的 id 查询到文章的详情信息。
在这里插入图片描述
咋一看好像没有问题。但是确实有问题
在这里插入图片描述
这就很好奇了文章的 uid 是 1对应着 用户表中 admin 用户。
就是说文章的作者确实是存在的。
那为什么 userinfo是 null 呢
原因很贱我们的实体类有这哥属性但是文章表里没有这个字段啊
在这里插入图片描述
这个时间resultMap 就上场了。因为 resultType 它不行

可参考对数据表进行“增删查改”的进阶操作
在这里插入图片描述
在这里插入图片描述
此时我们就实现了一对一查询。存在问题
【association 标签就是用来实现一对一情况的多表查询】
虽然存在一些问题
UserInfoMapper 中 resultMap 配置的字段信息不完整。
导致虽然查询结果的信息是完整但是没有完整映射到 ArticleInfoMapper 的 userinfo 属性中。
在这里插入图片描述
这里可以体现出一个结论
在 本身 xml 文件是可以不用映射所有属性的信息。
因为 它是自己调用自己所以不需要 resultMap 将属性全部映射都能自动完成所有属性的映射。
而 想要在一个 resultMap 中 调用 另一个 resultMap 中信息只能是它映射了的信息。
否则无法获取。
所以我们来讲 UserInfoMapper 中 resultMap 对于属性的映射补全再来看个效果。在这里插入图片描述
这里还存在着问题
在这里插入图片描述
到头来结果发现还是存在问题的。
当一个属性在两个数据表中都存在时默认读取的是 本身的字段值。
也就是说不光是上面的两个我们演示的那个情况出现的那四个属性都是这个情况。
在这里插入图片描述
下面我们来分析解决这个问题。
同时加深对这个问题的印象。
在这里插入图片描述
这个时候我们才真正完成了 一对一关系的多表查询


MyBatis 多表查询一对多关系

一对多关系⼀个⽤户可以是多篇⽂章的作者。
⼀对多需要使⽤ < collection > 标签⽤法和 < association > 是一样的 .

为什么使用 collection标签其实很理解。
看中文意思就明白了
association 的中文就是关联放到使用场景中就是将 2个表联系起来。

collection 的中文意思就是 收集把它理解为集合将多个表收集起来整合。
当然这些表肯定都与一张表有关系不管怎么叫做 一对多
放在实例中多个表对应着多篇文章
这多个表中有一个相同字段且信息是一样的。【作者id是一样即是同一个人写的】
由这个作者id就可以把所有文章是他写的文章给映射起来建立关系。
这就是 一对多 关系。

在实现一对多关系查询之前我们先来做一些准备工作。
首先我们来用户表的实体类进行处理。
在这里插入图片描述
下面我就来实现这个一对多的关系查询。。
实现一个 根据用户id获取用户和他缩写的文章信息。
在这里插入图片描述
换句来说
一对多关系的查询相比于 一对一关系的查询就是把 resultMap 中的 association 标签换成了 collection 标签。
里面的内容一点都没改。


复杂情况动态SQL使⽤

动态 sql 是MyBatis的强⼤特性之⼀能够完成不同条件下不同的 sql 拼接。
可以参考官⽅⽂档Mybatis动态sql
进去之后就是这个页面
在这里插入图片描述
你会发现 动态SQL被拎出来放目录里说明什么
说明它重要啊 不然我也不会给它一级标题啊。


动态标签 - < if >标签

在注册⽤户的时候可能会有这样⼀个问题如下图所示:
在这里插入图片描述
回顾我们之前实现的功能查询你会发现参数全部都是确定的就是写死了的。
在这里插入图片描述
都是抱着那种前端一定会传给我数据的 “ 态度 ”也就是认为一定会拿到必要参数
但是在实际业务场景中会存在一些非必传的参数。
就是说必要参数有时候是不会传输的很有可能传过来的参数是没有的。
那么面对这种情况我们在程序中该如何处理
在这里插入图片描述
下面我们就来具体实现这个业务。
在这里插入图片描述
但是存在着一个问题如果参数很多而且每一个参数都是非必传参数。
那么我们需要对每一个参数进 if 标签来判断。
这就非常的麻烦可能会多敲字符导致SQL出现问题。
这个时候就需要借助 trim 标签了。
具体怎么使用看下面对 trim 标签的介绍和使用。


动态标签 - < trim >标签

之前的插⼊⽤户功能只是有⼀个字段可能是非必传如果有多个字段⼀般考虑使⽤ < trim >标签 结合 < if >标签对多个字段都采取动态⽣成的⽅式。
< trim >标签中有如下属性
prefix表示整个语句块以prefix的值作为前缀
suffix表示整个语句块以suffix的值作为后缀
prefixOverrides表示整个语句块要去除掉的前缀
suffixOverrides表示整个语句块要去除掉的后缀

说白了trim 就是为了方便程序员 去除 开头 /末尾 的 某个符号
也就是说在 开头/结尾 多写了这个符号是没有问题的。
因为 trim 会将它删除掉。
如果没多写也不会影响 程序的运行。
在这里插入图片描述
下面我们来实战演练一波。
在这里插入图片描述


动态标签 - < where >标签

传⼊的⽤户对象根据属性做where条件查询⽤户对象中属性不为 null 的都为查询条件。
如user.username 为 “a”则查询条件为 where username=“a”
where标签主要作用实现查询中的 where 替换的。
什么意思呢
原先我们写的 where 是 SQL 的一部分是SQL的关键字。
现在我们使用 MyBaits 提供是 where 标签来代替 SQL 中 where 关键字 。

那么有的人可能会有疑问; 这替换跟没替换一样还多敲 几个箭头。
因此会产生一个问题 使用 where 标签 的好处都有哪些
不然不会创造出一个 where标签出来。
如果没有任何查询条件的情况下where 标签 可以实现 隐藏 SQL 的 where 的SQL部分但如果存在查询条件那么会生成 where的 SQL并且 where 标签可以自动的去除最后一个 判断条件的 and 字符。

也就是说我们在拼接多个条件的时候有几个条件涉及到非必传参数。
会有一个什么情况呢
通常 我们拼接多个条件的时候要么使用 or或逻辑要么使用 and与逻辑。
A and B
当 A 条件缺少判断的参数的时候就会将 A 和 后面 的 and 去除掉。
这个and也就是最前面一个 and 嘛。
就变成一格判断条件的 SQL了。

下面我们来实战一下。
在这里插入图片描述
虽然比直接敲SQL要复杂一点点。
但是构造 SQL的灵活性大大提高

还有一个去除 and 的功能对吧
我们再来搞一下。
在这里插入图片描述
如果 and 放在后面就是说 and 后面没有判断条件或者说 缺少 参数无法构造 where SQL。会出现什么状况
我已经帮你们测了报错
在这里插入图片描述
其实这个问题也很好解决。直接给你们演示个大概。
在这里插入图片描述
以上标签也可以使⽤ < trim prefix=“where” prefixOverrides=“and” > 替换。
无非就是 少用几个属性。


动态标签 - < set >标签

根据传⼊的⽤户对象属性来更新⽤户数据可以使⽤标签来指定动态内容。
UserMapper 接⼝中修改⽤户⽅法根据传⼊的⽤户 id 属性修改其他不为 null 的属性
这么说吧。set 标签和 where 是一样。
都是替代 SQL 中的关键字。
set 就是 update 操作所需要使用的关键字。
而且也是和 if 标签 配合使用的。

而且和 trim 标签一样。可以去掉最后一个符号一般都是逗号。
在这里插入图片描述
实战演示一波。
在这里插入图片描述
那如果没有 逗号呢会是什么效果
下面我们把三个非必传参数都传递。
在这里插入图片描述
以上标签也可以使⽤ < trim prefix=“set” suffixOverrides=“,” > 替换。


动态标签 - < foreach >标签

对集合进⾏遍历时可以使⽤该标签。< foreach >标签有如下属性
collection绑定⽅法参数中的集合如 ListSetMap或数组对象
item遍历时的每⼀个对象集合中的元素
open语句块开头的字符串类似 trim的 prefix
close语句块结束的字符串类似 trim的 close
separator每次遍历之间间隔的字符串间隔符
【PSforeach 标签是 trim 所不能替代的】

应用场景
通常我们要删除数据库中的信息不是一条一套的删。
而是一删一大把。
比如
我们要根据id来删除 记录我们就把这些id 弄成一个结合。
在这里插入图片描述
此时就可以通过 foreach 标签进行遍历传参删除对应的信息。
这样做的效率就很高一次调用就可以将需要删除的数据全部删除。

实战演示一波。
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6