Java Advanced - MyBatis Query Database && Spring Boot Unit Test - Details Crazy

Article directory

foreword

After the previous study, the basic operations of our Spring series have been almost realized. Next, let's learn more important knowledge, store the data passed by the front end, or query the data in the database.


1. What is MyBatis?

MyBatis is an excellent persistence layer framework that supports custom SQL , stored procedures and advanced mapping.
MyBatis removes almost all JDBC code and the work of setting parameters and getting result sets.
MyBatis can configure and map primitive types, interfaces and Java POJOs (Plain Old Java Objects, plain old Java objects) to records in the database through simple XML or annotations.
To put it simply, MyBatis is a simpler tool to complete the interaction between the program and the database, that is, a simpler tool to operate and read the database.
Mybatis official website analyzes and supplements MyBatis

as an excellent persistence layer framework .

MyBatis, is also an ORM framework.
ORM (Object Relational Mapping), that is, object relational mapping.
In the object-oriented programming language, the data in the relational database and the object are established in a mapping relationship, so as to automatically complete the mutual conversion between the data and the object:
1. The input data (ie the input object) + SQL is mapped to native SQL
2. Map the result set to the returned object, that is, the output object

ORM maps the database to an object:
database table (table) >>> class (class)
record (record, row data) >>> object ( object)
field (field) >>> object attribute (attribute)
The general ORM framework will map each table of the database model to a Java class.
That is to say, using MyBatis, you can operate the tables in the database like operating objects, and can realize the conversion between objects and database tables.

That is: MyBatis can be called a "bridge".
Its function is to map the database and the program.
After mapping, you can do a series of operations.
For example:
query, since we map the database and the program, we directly map the entire data table to a class.
The result of the query is a collection, which stores the objects of the class (the inserted rows of records), and the data is also queried.

Save, still the same, we have mapped the database and the program, and got the data in the table into the object. Then when we call a method of the object, can we directly save the members of the object directly to MySQL!

MySQL and MyBatis are different.
MySQL, provides a data access (data management) software.
MyBatis is an "intermediate bridge", which is used to connect programs and databases, establish relational mapping, and perform data operations in the middle layer (persistence layer).

In general:
MyBatis definition: MyBatis is an excellent ORM (Object Relational Mapping) persistence layer framework.
Its role: to realize the data interaction between the program and the database.

PS:
The ORM framework is not only MyBatis!
It's just that MyBatis uses a wide range of standard adhesives in China, accounting for more than 90% of the Chinese market.
The most used abroad is Hibernate.

As for the reason, the difference between MyBatis and Hibernate and so on. . .
Including Hibernate, there is another Spring JPA, and it has and difference?
I'll tell you after MyBatis is finished.
(The premise is that I still remember, if you don’t write it, you can Baidu it yourself)

MyBatis supports custom SQL

Custom SQL, including a wide range.
The "CURD" statement in the database can be implemented.
For custom SQL, we can write whatever SQL we want to write.
From this, it is not difficult to see one of the biggest features of MyBatis: flexibility!
This is also an important reason why MyBatis is popular in China! ! !

The reason behind it is that the needs of domestic users are really weird and uneven! !

Take an example from life:
almost all universities have computer majors.
but! Which school has a major in Internet products? No! ! !
The university does not teach, and there are few training classes outside.
Most of them are training courses for postgraduate entrance exams, followed by computer training.
The development of computer is still relatively mature.
but! Regarding the training of product managers and products, basically the institutions that do this training.
I haven't seen it anyway.
The reason is because its market share is not high and no sign of interest can be seen.
Naturally, it will not do this with people.
Let's put it this way: In some companies, there is no product manager, the position.

Therefore, most of the product managers we meet in the future only have a mouth and will ask for needs, but I don't know how complicated this demand is to realize!
Because there is no training, and most of the current product managers do not understand technology,
therefore, their demands are all kinds of strange.
So there is the joke about the phone case, which is completely bullshit.
One piece of software, one piece of hardware, two things that can't be beat.

Therefore, the role of MyBatis flexibility is reflected.
Just to meet various needs.

In foreign countries, technologies and products have been streamlined and trained.
After all, foreign countries are the origins of computers, and it is easy to understand that they are developing rapidly.
The development is extreme, and it is stable.

stored procedure

The SQL I used before , no matter if it is Dorma complex SQL, we can solve it with one line of SQL.
Because in SQL, there is no particularly complicated business, such as for loop and if judgment. . . None of these.
It is a very smooth, single-dimensional SQL operation, which is for ordinary SQL.

but! Stored procedure is a method in SQL, which is composed of a lot of SQL.
In this composition, it has loops, judgments, branches, and variable transmission.
This is called a stored procedure, that is, the method of SQL.
Conversely understand:
what is produced by the process of SQL method is called a stored procedure.

Later, after we work, others give us a stored procedure, which is densely packed with SQL statements.
There are also if judgments, for loops, setting the value of variables...
Then, input parameters, output parameters, anyway, it is a large string of SQL statements.
As few as dozens of lines, as many as thousands of lines.

So why don't we programmers use this stored procedure?
This is actually related to the characteristics of stored procedures.
Although stored procedures can achieve complex business, but! This just moves the business from the program side to the SQL side.
In this case, the company's requirements for programmers will be very high! ! !

Just imagine: the company gave a stored procedure, a SQL statement with hundreds of lines, you probably spent your eyes.
If you can understand it, there is a ghost. . .

But someone has to do it, and this is the birth of a special professional DBA.
DBA: Database Administrator - database administrator, also known as database development engineer.
His SQL is very good, he does not need to write programs.
Every day is fiddling with SQL statements, only playing with databases, playing with data.

For most programmers: they don't understand stored procedures at all, such a complicated thing!
Also, there's something very, very hard to use in stored procedures!
When we are typing a very complex java code, we can debug step by step through debug, enter classes, methods, and properties to observe the runtime status. This can help us troubleshoot errors in the program. Also in time the program can be debugged.

But stored procedures cannot be debugged.
That is to say: a stored procedure, with these hundreds of lines of SQL statements, requires us to write.
Moreover, there is an error, and the error can only be checked by the naked eye. [Debugging is not supported]
I dare say: 90% of programmers can't do this.
This is a job that only true genius can do.

but! Don't worry too!
It is also impossible for the company to let us programmers do this.
It is generally performed by external professionals.
Stored procedures are most commonly used in hospitals.
The hospital needs to summarize (various reports) data (income, attendance...) every day, every month, and every year.
In short, there is a lot of data involved.
This requires extracting data from various data tables.
At this point, a simple SQL statement will not work.
At this time, the stored procedure will be used.

Due to the difficulty of the stored procedure, it is very big!
The demands on people are very high, and with them comes high wages.
Probably more than 1.5 times the salary of our programmers.
That is: recruit a programmer to agree on a salary of 10,000 yuan, then the salary of the DBA should be at least 1w5 or more, otherwise you can't find anyone.

Advanced Mapping

Advanced mapping can realize one-to-one multi-table mapping and one-to-many mapping in addition to data table and object mapping in the program. For example: Every blog post on

CSDN has its author. The relationship between the blog post and the author is a one-to-one relationship. At this point, using MyBatis, you can perform a table query when querying, and map the queried data results to one of my article objects. Then again, an author, he can publish many blog posts. From this perspective, the author has a one-to-many relationship with the blog posts he publishes. In this case, using MyBatis can also achieve this task. MyBatis can directly query the data in the database, and then assign the data to UserInfo. This UserInfo has an attribute (list article - article list). It is used to record the works created by the author.









MyBatis removes almost all JDBC code and the work of setting parameters and getting result sets.

In the past, when we were doing JDBC programming, we needed to obtain the data source object (DataSource), and then set three attributes URL (data source path), user name (default is root), password (MySQL login password).
After setting these three items, you can connect to the data and perform a series of operations.

In addition, when obtaining the result set, we need to use an object of a class (ResultSet) to receive the result set returned by the database, and we need to use the iterator to perform subsequent printing.

With MyBatis, you don't need to put on shoes.
It will automatically help us realize the mapping,
we only need to write the SQL statement (do not write wrong), after writing, it will execute the SQL statement, and directly map all the query results (table data) to the object.
That is to say: we do not need to write a single line of code for the pre-operation of JDBC.
MyBatis is directly all-inclusive, you can use it directly.
Very cool!

MyBatis can configure and map primitive types, interfaces and Java POJOs (Plain Old Java Objects, plain old Java objects) to records in the database through simple XML or annotations.

When MyBatis is implemented, it has two implementation methods:
1. Implement data operations through xml, and data operations support all types.
This was a mainstream operation method before MyBatis version 3.1.
Use the form of xml to implement the "CURD" operation on the database.

but! After version 3.1, MyBatis has new options.
That is the second method (annotation method).
But the current mainstream is still using the xml form.
why?
Let's not say that MyBatis is very flexible to use!
Flexibility comes at a price!
The price is that we have to write SQL statements.
Just think about it: is it awkward that we write a SQL statement in the annotation?
There is not much code, but the comments are very long.
Therefore, after version 3.1, MyBatis provides a new way of manipulating data by annotation.
It doesn't work either because it doesn't work.
The annotation method is still possible to implement simple SQL operations.
but! Once the SQL statement is a little more complicated, it will be particularly awkward when you use it.
Comments are longer than code. . .
And xml is more flexible to write SQL statements, and it will not feel awkward, easy to use!

Therefore, this article is also based on xml to realize the operation of the database.


Why learn MyBatis

For back-end development, the program consists of the following two important parts

1. Backend program
2. Database
insert image description here

To communicate, these two important components must rely on database connection tools. What are the database connection tools? For example, JDBC
, which we learned before , and MyBatis, which we will introduce today, already have JDBC, so why should we learn MyBatis?

This is because the operation of JDBC is too cumbersome. Let's review the operation process of JDBC:
1. Create a database connection pool DataSource
2. Obtain a database connection Connection through DataSource
3. Write the SQL statement to be executed with the ? placeholder
4. Create operation command object Statement through Connection and SQL
5. Replace placeholder: specify the database field type to be replaced, placeholder index and value to be replaced
6. Use Statement to execute SQL statement
7. Query operation: return result set ResultSet, update operation: return the number of updates
8, process the result set
9, release resources
Example code - insert operation - intercept the content of my own article.
insert image description here
It can be seen from the above code and operation process that for JDBC, the whole operation is very cumbersome. We not only need to splicing each parameter, but also operate the database step by step according to the template code, and After each operation, manually close the connection, etc., and all these operation steps need to be repeated in each method. So we thought, is there a way to operate the database in a simpler and more convenient way?
The answer is yes, this is the real reason why we want to learn MyBatis, it can help us operate the database more conveniently and faster.
Before using jdbc, it required nine steps, but now using MyBatis, just write a method, and a SQL will do it. Like manually releasing resources and processing result sets, we don't need to do it anymore. MyBatis "nanny-level" assistant.


How to learn MyBatis?

The focus of this article is divided into two parts:
1. Configure the MyBatis development environment (create an SSM project)
2. Use the MyBatis schema and syntax to operate the database


1. Create a MyBatis project

Preparation: create database and data table

Next we will create a database mycnblog about blogs
and create three tables in the mycnblog database.
Here's the code for you, Dai! "Murder" is hidden inside.
It will lead to a bug, otherwise there is a solution,
just do it first.

But there is one thing to be aware of!
In the content field of the article table, its type is text.
text can represent limited text content. In practice, longtext is generally used.
In addition, for the createtime field, we use a now method. This now method requires the MySQL version, which is above 5.5.
But it shouldn't be a big problem. After all, the database version we use with jdk1.8 is version 5.7.

Look carefully at the SQL creation below. Whether it is creating a database or a data table, I have set the character set to utf8.
Make sure that it supports Chinese.
The advantage of this is that even if you do not modify the configuration of the database, the created table still supports Chinese.

One more small detail: In the SQL statement that adds a user information, our password is stored in clear text.
If you write it like this, you will definitely be criticized by the interviewer.
Even if you use md5 for encryption, it doesn't really do much.
If it's just an md5, we can actually use the " rainbow table " to exhaustively get your password. (Attention! This is not decryption, it is the possibility of enumerating your passwords)
Someone can think of it:
the password can be exhaustively obtained through the rainbow table in the case of one md5.
So what about the password md5 twice, or even more?
Can the rainbow table be broken? ?
You can think of it, other hackers can't think of it? ?
Don't say it twice, even if you do it 3 times, 4 times, or even five times, people will deal with it.
Moreover, no matter how many times you encrypt with md5, it is actually a cumulative effect. For hackers, it is nothing more than a few exhaustive attempts.
The most reliable way is to have random numbers and variables.
This is more reliable!
Because it is randomly generated, there is no rule at all!
It is very difficult to get the password!
almost impossible.

-- 创建数据库
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);

Open your local MySQL, copy and paste the above SQL into MySQL.
PS: It is recommended to copy to a text file first, and then copy to MySQL.
Because if you copy the above content directly, the SQL will be crowded into a pile.
That is, without formatting.
insert image description here
You put the above code in the notebook first, and then paste it into MySQL.
Not only are they not crowded together, but all the SQL is executed, only the last SQL sentence is not executed.
Just go back and everything is OK.
insert image description here
Let's see if the data is inserted successfully
insert image description here


1.1. Add MyBatis related dependencies

Sharp-eyed friends will notice that I use the adjective "relevant".
Yes, if we want to use MyBatis, it is not enough to introduce MyBatis dependencies.
We need to introduce a dependency (on the database).

Two scenarios will be involved here:
1. When the project is created, introduce MyBatis related dependencies
2. For old projects, add MyBatis


1. Create a new MyBatis project


insert image description here
insert image description here
Then, delete the useless files.
insert image description here


2. Introduce MyBatis related dependencies into the old project

This has been said many times and added using the Edit Starter plugin.
insert image description here


1.2, configure the database connection string

不要立即启动项目!!!!
如果立即启动项目,就会报错。
指针对 社区版 idea,专业版会帮助我们自动生成关于 数据库的 配置信息。

社区版:
这是因为 没有配置 关于 数据库的数据源的 URL
insert image description here

专业版:
直接就给我们配置好了。
insert image description here

现在我把的配置文件删除掉,重新创建一个配置文件,与社区版保持一致,我们来重新编写配置信息。

我们需要配置 4 项:
insert image description here
此时,我们再启动项目,就不会报错了。
insert image description here


1.3、配置 MyBatis 保存的 xml 的目录

我们前面说过 MyBatis 有两种 操作方法:
1、使用 xml 的形式 实现呢
2、 注解(MyBatis 3.1版本之后,开始提供)
但是!
注解的方式,并不好用。
因此,我们主要还是关注 xml 形式,是如何操作 数据库。

思考一下:
xml 是一个 资源文件,对不对?
那么,xml 文件,还是放在 resource 目录下。
还有一个问题:
放在 resource 哪个 目录底下。

需要注意的是:一般是不会将其放在 resource 根目录底下,与配置文件处于同一级目录。
因为到时候,配置文件,非常多!
此时,你放进去,不就是添乱嘛!!!

通常我们都是在resource 目录下,创建一个子目录,用来存放的。
insert image description here


使用 MyBatis 的操作模式 操作数据库

MyBatis 的操作模式

insert image description here

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 的 操作模式,就是在讲下图中的两个文件。
insert image description here
这两个配合起来,就能生成 数据库可以执行的SQL语句,并且执行 SQL,操作数据库。
并将 结果 映射到程序的对象中。


第⼀个MyBatis查询:实现一个根据用户id来查询用户信息的操作

我们要实现一个 根据 用户id 来查询用户信息的操作。
前面我们在准备工作中,就是已经给 userinfo 表中插入了一个数据。
insert image description here
下面,我们就来完成这样的一个功能。


1、定义接口

insert image description here


2、创建 xml,实现上面的接口

xml 文件,不能随便创建。
我们在配置文件中,已经指定了 xml 文件存储路径。
并且,命名规则也指定了。
insert image description here
我们必须按照规则来。
insert image description here
至于 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值。
insert image description here
namespace 的值,是需要我们手动去填写的。
填写的内容:是需要时实现的接口位置 >> 包名 + 接口名称。
insert image description here
接下来,就是在 xml 文件中,实现 UserInfoMapper 接口 中的 方法。
insert image description here
关于获取方法参数,使用的 ${} 和 #{} 的区别,后面会详细讲。
&enso;
好,关于 MyBatis 的操作,就都完成了。
下面,我们就可以来验收成果了。


运行结果展示

我们在 service 包底下创建一个 UserInfoService 类。
在里面 写一个方法, 去 调用 UserInfoMapper 中的方法。
然后,在 controller 包下,也去创建这样的一个类,去调用 UserInfoService 中的方法。
insert image description here
此时,我们将项目启动起来。
insert image description here


注意!有的人可能会在这一步出现问题

insert image description here

我被坑的头皮发麻。
第一次遇见版本不匹配,引起的错误。
看异常信息检查不出错误。
出现这个问题的原因是:我们添加的 MyBatis r的版本太高了,而我们使用的 Spring Boot 版本太低了(阿里云提供的)。导致的版本不兼容。
因此 URL 不能像正常情况下,那样去配置。
insert image description here
应该这样去配置
insert image description here
更简单解决方法的是:使用官方 提供的Spring Boot 框架,选择次新的。
insert image description here
我使用的是 阿里云,所以 版本很低,我是用的版本是 2.3.7。
所以,才会出现上述情况。


MyBatis 执行过程

insert image description here

在这里,我在补充一点。
我们在写 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、如果中途修改了代码,在项目打包的时候会发现错误,因为打包的时候会自动执行单元测试,单元测试错误就会发现。
这一点最重要!
insert image description here
3、单元测试,最大的一个好处 :
让我们非常方便,非常直观,也非常直接的,在写完一个功能之后,立马就能知道这个功能是否是正确的!
这也是我们学习单元测试的初衷,就是为了降低 测试 mybatis 功能的成本。

4、不使用单元测试的时候,它是会 “ 污染 ” 本地的数据库的!
就是比如说:
我们实现了一个 添加 功能,我们要去测这个添加功能。
这就需要正儿八经的去进行添加操作的。
这就会对本地数据库中的数据,发送变动。
这就是 “污染”!

然而,如果使用了 单元测试 来测试功能,.
测试单元,就能保证在 测试完功能之后,对于数据库中的数据没有任何影响!

这个牵扯到了 事务的回滚机制。
这是 我在讲 MySQL是如何保证事务的原子性 的 时候,提到过的 事务回滚机制。
有兴趣,就自己去看,目录给你标出来了。
insert image description here
单元测试,也是通过利用 数据库的回滚机制 来 避免对 数据产生 “ 污染 ” 。
也就是说:我们在执行单元测试之前,MySql 为其创建了一个事务。
【MySQL 默认情况下,是处于开启事务的状态,也就说开启了事务的自动提交】
然后,开始执行单元测试,对数据库中的数据进行操作。
在验证完 单元的功能没有问题之后,就会进行事务的回滚操作。
还原到 还没有测试的情况。【将数据还原到初始状态】


3.Spring Boot 单元测试使用

Spring Boot 项⽬创建时会默认单元测试框架 spring-boot-starter-test,⽽这个单元测试框架主要是依靠另⼀个著名的测试框架 JUnit 实现的,打开 pom.xml 就可以看到,以下信息是 Spring Boot 项⽬创建是⾃动添加的:
PS:我用来演示效果的项目,是我一步一步带着大家创建的。
所以,作假含量极低。我可没有偷偷添加这个依赖!
都是 Spring Boot 干的!!!雨我无瓜!
insert image description here
这里有一个细节:
insert image description here


&enspp;

单元测试的实现步骤

1.⽣成单元测试类

insert image description here

这个时候,此⽅法是不能调⽤到任何单元测试的⽅法的.
此类只⽣成了单元测试的框架类,具体的业务代码要⾃⼰填充。


2 添加单元测试代码

1.添加 Spring Boot 框架测试注解:@SpringBootTest

至于为什么还需要加一个 测试注解,是因为 我们生成测试类,是一个普通的类。
insert image description here
但是!测试接口,它是一个普通的接口吗?
insert image description here
因此,我们需要在测试类上 声明它要测试的方法,是运行在 Spring Boot 容器当中的。
所以,@SpringBootTest 注解,就是起着这样的一个声明作用。
表示当前这个类中 测试方法(测试单元) 是运行在 Spring Boot 中的。
insert image description here


2.添加单元测试业务逻辑

insert image description here


3、开启测试

insert image description here

虽然,从打印的结果来看,功能是没有的。
而且,左边那几个 绿色勾勾,代表测试通过。
insert image description here
但是! 我们是使用 的 sout 语句,来对查询结果进行输出。
这并不是 我们 单元测试的效果!!!!
单元测试的效果应该是 单元测试中的断言!!!

断言:
就是说:以什么为标准,
通过这个标准来衡量 测试是否通过。
比如,如果 断言的结果为 true,就表示 单元测试 通过了。
反之,断言的结果为 false,就表示 单元测试 不通过。
并且!断言之后的代码,是不再执行的!!!

所以。还没有完。
单元测试,还有一部分是关于 断言 的 内容。
我们是需要知道的。


4、简单的断⾔说明

由 Assertions 类提供的,注意!这个类是 JUnit 提供的
insert image description here
下面,来跟着我看一下,如何使用断言,来判断单元测试是否通过!
insert image description here
这就是断言的魅力,一旦出错。
如果测试失败,它的报错信息会非常非常的详细!

后面,我们实现 增,删,该2的时候,就不需要 浏览器 和 postman了。
直接使用断言,来测试即可。

这里做一个小拓展:
为什么有些人的 科学版 idea, 在进行 与 @Mapper 相关的属性注入,使用 @Autowired 来注入,为什么会报错?
insert image description here


拓展:“小鸟” - 插件 MyBatisX

它能够帮助我们快速切换 接口 和 xml。
让我们操作 MyBatus 更舒服。
而且,还能帮我们自动去生成代码。
insert image description here


增、删、该操作

接下来,我们来实现⼀下⽤户的增加、删除和修改的操作,对应使⽤ MyBatis 的标签如下:
< insert >标签:插⼊语句
< update >标签:修改语句
< delete >标签:删除语句

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


MyBatis 修改操作

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

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

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


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

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

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

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

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


MyBatis 删除操作

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


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

insert image description here


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

注意!只有 select 标签,特殊一点(需要指定返回类型)。
delete 标签 和 update 标签都是一样的。
insert image description here


单元测试 - 验证功能效果

insert image description here

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


MyBatis 插入操作

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


先实现最简单 的 插入操作

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

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

insert image description here


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

insert image description here


3、进行单元测试

insert image description here

算了,为了防止你们认为我做假。
我 “污染”一条 王五的信息。
insert image description here


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

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


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

insert image description here

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

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

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

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


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

返回受影响的行数 和 自增 id
insert image description here


我们测试一下。

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

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


查询操作

单表查询

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

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

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


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

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

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

你可能觉得这麻烦,但是其实!预查询是为了提高查询效率的。
举个例子:insert image description here

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

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

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

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

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

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

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

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

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

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

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

NO!
存在,即有意义!【蚊子除外!】
下面,我们来看 ${} 的使用场景。
insert image description here
其实,与其说是 ${} 的优点,不如说是它的专长!
毕竟 这任务,#{} 做不了,只有它能做!

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

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

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


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

insert image description here

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

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

我们再来试一下:把 $ 改成 # ,效果会如何?
insert image description here
由此,不难得出结论:
使用 #{} 是不存在 安全漏洞滴!!!
是非常nice的。


like 查询 - 特殊情况

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

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

那么,怎么解决这一个问题呢?
使用concat拼接方法,就可以解决问题了。
insert image description here


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

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

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

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

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

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


多表查询

前置知识

返回类型:resultType

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

返回字典映射: resultMap

resultMap 使用场景:

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

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


resultType && resultMap 的区别

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

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


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

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


MyBatis 多表查询:一对一关系

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

insert image description here
如果你们的content 出现乱码,反正就不是中文。
你就可以参考这篇文章MySQL第二讲,在文章的最后讲了如何配置字符集的问题insert image description here

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

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


MyBatis 多表查询:一对多关系

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

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

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

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


复杂情况:动态SQL使⽤

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


动态标签 - < if >标签

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


动态标签 - < trim >标签

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

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


动态标签 - < 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了。

下面,我们来实战一下。
insert image description here
虽然比直接敲SQL,要复杂一点点。
但是,构造 SQL的灵活性,大大提高!

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


动态标签 - < set >标签

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

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


动态标签 - < foreach >标签

This tag can be used when traversing the collection. The <foreach> tag has the following attributes:
collection: the collection in the binding method parameters, such as List, Set, Map or array objects
item: each object (element in the collection) during traversal
open: the character at the beginning of the statement block String (similar to the prefix of trim)
close: The string at the end of the statement block (similar to the close of trim)
separator: The string (spacer) of the interval between each traversal
[PS: foreach label, which cannot be replaced by trim!

Application scenario:
Usually we want to delete the information in the database, not one by one.
Instead, delete a lot.
For example:
if we want to delete records according to id, we make a combination of these ids.
insert image description here
At this point, you can use the foreach tag to traverse the parameters and delete the corresponding information.
This is very efficient, and all the data that needs to be deleted can be deleted with one call.

A wave of practical demonstrations.
insert image description here

Guess you like

Origin blog.csdn.net/DarkAndGrey/article/details/126103652