MyBatis Practical Guide: Exploring the Art of Flexible Persistence


foreword

In the field of software development, the choice of the persistence layer framework plays a vital role in the realization and maintenance of the project. As an excellent persistence layer framework, MyBatis has been widely concerned and applied for its flexibility, high degree of customization, and direct control over SQL. This article will explore the MyBatis framework in depth, from initial knowledge to practical application, and gradually reveal its key role in modern software development.

1. Getting to know MyBatis for the first time

1.1 What is MyBatis

MyBatis is an excellent open source Java persistence layer framework, which is used to simplify the process of database access and operation. It allows developers to use a simple method XML或注解配置to map the relationship between Java objects and database tables, so as to realize the persistent operation of the database. MyBatis is not a comprehensive ORM (object-relational mapping) framework, but more emphasis on precise control of SQL, enabling developers to write and optimize SQL statements more directly.

ORM (Object-Relational Mapping) framework:
ORM, the full name of Object-Relational Mapping (Object-Relational Mapping), is a software technology used to combine object models in object-oriented programming languages ​​(such as Java, Python, etc.) Mapping and transformation between data models in the database. Simply put, the ORM framework allows developers to use object-oriented thinking to operate databases without directly writing SQL statements.

The core idea of ​​MyBatis lies in the decomposition of SQL, which 将 SQL 语句与 Java 代码separates, thereby reducing the coupling of the code and providing greater flexibility and maintainability . By configuring the mapping file (Mapper XML), developers can clearly define the mapping relationship between SQL statements and query results, while Java codes focus on writing business logic. In addition, MyBatis also supports features such as dynamic SQL, parameter binding, and caching, making database operations more efficient and convenient.

1.2 Why learn MyBatis

For back-end development, the program is composed of the following two important parts, namely the back-end program and the database.


For these two important components to communicate, they must rely on database connection tools, such as the previous JDBC and the current MyBatis framework, both to connect and operate the database.
However, the operation of using JDBC will be very cumbersome, so you need to use other simpler and more efficient database connection methods, and MyBatis is a better choice.

As a persistence layer framework, MyBatis has many advantages and values ​​in modern software development. The main reasons for learning MyBatis are:

1. Flexible SQL control: MyBatis allows developers to directly write and control SQL statements, which is very useful for scenarios that require precise control and optimization of database operations. Developers can write their own SQL statements and adjust them according to specific needs without being limited by the automatically generated SQL.

2. Good performance: Since developers can optimize SQL statements to make them more suitable for specific database and query requirements, MyBatis has excellent performance. Properly written and optimized SQL statements can significantly improve the database access efficiency of applications.

3. Adapt to different databases: MyBatis supports a variety of databases, so no matter which relational database (such as MySQL, Oracle, SQL Server, etc.) is used, MyBatis can adapt and provide a consistent mode of operation.

4. Good scalability: MyBatis allows developers to write custom TypeHandlers, Plugins, etc. to meet specific needs, thereby enhancing the scalability and customization of the framework.

5. Lightweight framework: Compared with some heavyweight ORM frameworks, MyBatis is a relatively lightweight framework with low learning costs and relatively easy to use.

6. Can be integrated with other frameworks: MyBatis can be easily integrated with other popular frameworks (such as Spring, Spring Boot), making the overall development process smoother.

7. Better understand the database: By learning MyBatis, you will not only learn a framework, but also have a deeper understanding of the working method and performance optimization method of the database, which is very helpful for database design and application optimization.

2. The positioning of MyBatis in the software development framework

It is very important to understand the positioning of MyBatis in the entire software development framework, especially for understanding its role and role in the system architecture. The following is a simple interactive flowchart showing the position and interaction of MyBatis in the entire application architecture:

In the above process, MyBatis is mainly located in the persistence layer (Persistence), and its role is to encapsulate and manage the interaction between business logic and database . The following is the interaction between the layers:

  1. Front-end interface : This is the user interface of the application through which the user interacts with the system and sends requests.

  2. Control layer (Controller) : The control layer receives requests from the user interface, handles the distribution and scheduling of requests, and calls the appropriate service layer for business processing.

  3. Service layer (Service) : The service layer contains the business logic of the application. It receives requests passed by the control layer, processes business logic, and may need to interact with the persistence layer for data.

  4. Persistence layer (Persistence - MyBatis) : MyBatis is located in the persistence layer, which is responsible for converting data access requirements in business logic into operations on the database. Through mapping files (Mapper XML) and corresponding interfaces (Mapper Interface) for relational mapping , MyBatis manages the data conversion between Java objects and database tables.

  5. Database (DB) : The database is where the actual data is stored. MyBatis performs actual database operations through SQL statements, and reflects operations such as data storage, retrieval, and update to the database.

In this process, MyBatis acts as a bridge in the persistence layer, responsible for connecting business logic with database operations . It allows developers to define the relationship between database tables and Java objects through mapping files or annotations, so as to realize data access. This positioning enables developers to take full advantage of the performance and functionality of the database while maintaining code maintainability and scalability.

3. Create a MyBatis project based on Spring Boot

3.1 Add support for MyBatis framework

  1. Create a Spring Boot project

  1. Add MyBatis dependency

When creating a Spring Boot project, if you want to create a MyBatis project, you need to check it in the dependencies. MyBatis FrameworkIn addition, you need to check a specific database driver, such as MySQL Driver.

3.2 Configure the database connection information and the storage path of the mapping file (Mapper XML)

After creating the Spring Boot project, you also need to configure application.ymlthe database connection information and the storage path of the mapping file (Mapper XML) for MyBatis in the configuration file.

The content of the configuration is as follows:

# 配置数据库的连接字符串
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/database?characterEncoding=utf8
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

This part of the configuration is used to set the database connection information. urlYou need to modify the , usernameand fields according to the actual situation passwordto connect to your own MySQL database. The driver-class-namefield specifies the class name of the MySQL database driver.

# 设置 Mybatis 的 xml 保存路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml

This part of the configuration sets Mapper XMLthe save path of the file. mapper-locationsfield specifies that MyBatis should classpath:mapper/look for files under the path Mapper XML. MyMapperFirst, you need to create a file corresponding to the interface in this path Mapper XMLbefore you can use MyBatis.

Fourth, the creation and use of MyBatis project structure

4.1 Preparation of database and tables

userinfoCreate a table and articleinfotables here :

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
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 timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';


-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
(1, 'admin', 'admin', '', '2023-8-09 10:10:48', '2023-8-09 10:10:48', 1);

-- 文章添加测试数据
insert into articleinfo(title,content,uid) values('Java','Java正文',1);
insert into articleinfo(title,content,uid) values('C++','C++正文', 1);
insert into articleinfo(title,content,uid) values('Python','Python', 1);
insert into articleinfo(title,content,uid) values('PHP','PHP正文', 1);

4.2 Create entity classes based on database tables

userinfoFor example, create an entity class for a table :

@Data
public class UserInfo {
    
    
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

The attribute names in the entity class generally match the fields in the database table for better compatibility. Here, the annotations in the Lombok library are used @Datato automatically generate methods such as getter, setter, equals, hashCode and toString of the entity class, which can reduce the writing of boilerplate code.

4.3 Create Mapper interface and XML mapping file

The above entity class already contains the attributes corresponding to the database table fields and the corresponding data types. Just make sure that the interface and documentation correctly match the entity class MyBatiswhen used. You can create a corresponding interface and file, and then use annotations to mark the interface.MapperMapper XMLMapperXML@Mapper

mapperCreate an interface under the directory UserMapper:


Among them, @Mapperannotation is an annotation in MyBatis, which is used to mark a Mapper interface whose interface is MyBatis, so as to tell MyBatis that this interface defines the method of database operation. In this interface, you only need to write code related to database operations, for example, to obtain all Userinformation:

import com.example.demo.entity.UserInfo;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    
    
    List<UserInfo> getAll();
}

Create an XML mapping file:

  1. First resourcescreate a mappersubdirectory under the directory to store Mapper XMLfiles:

  2. mapperCreate UserInfoMapper.javaan XML file corresponding to the interface under this path UserInfoMapper.xml:

  1. Then you need to fill this file with the following content:
<?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="com.example.demo.mapper.UserInfoMapper">
    
</mapper>

Among them namespace, the field specifies the path of the interface UserInfoMapper.xmlcorresponding to UserInfoMapper, at this time, the mapping relationship between the XML file and the interface is established.

When the plug-in is installed in IDEA MyBatisX, you can find a pair of birds. At this time, click UserInfoMapper.xmlthe blue bird on the side to adjust to UserInfoMapperthe interface mapped to it.

Conversely, clicking UserInfoMapperthe red bird in the interface will also jump to the corresponding UserInfoMapper.xmlfile.

At this time, it is found that the method in the interface will report an error, because there is Mapper XMLno corresponding SQL statement in the file.

Implement the SQL statement corresponding to the getAll method:

When UserInfoMapper.xmlwriting a SQL statement to query all users:


Among them, idthe field specifies the method in the Mapper interface corresponding to this SQL statement, that is getAll, resultTypethe field is the type of the returned data, and the object returned here UserInfo, the MyBatis framework will configure according to this mapping. After the query execution is completed, the Query results are automatically mapped into UserInfoobjects. But the prerequisite is to ensure that the attribute names in the entity class match the field names of the database table, so that MyBatis can correctly map the results.

4.4 Create service layer Service and control layer Controller

  1. Create a service layer servicedirectory, and create classes under that directory UserInfoService:
@Service
public class UserInfoService {
    
    
    @Autowired
    private UserInfoMapper userInfoMapper;

    public List<UserInfo> getAll(){
    
    
        return userInfoMapper.getAll();
    }
}
  1. Create a control layer controllerdirectory, and then create a class in that directory UserInfoController:
@RequestMapping("/user")
@RestController
public class UserInfoController {
    
    
    @Autowired
    private UserInfoService userInfoService;

    @GetMapping("/getAll")
    public List<UserInfo> getAll(){
    
    
        return userInfoService.getAll();
    }
}

At this point, the creation of the service layer and the control layer has been completed. The control layer is responsible for processing HTTP requests and the interaction with users and the service layer; while the service layer is used to process business logic related to user information and provide Return the result of processing. This structure conforms to the typical three-tier architecture (Controller - Service - Repository/DAO) design pattern, making the code clearer and easier to maintain.

In the above code, UserInfoServiceis responsible for calling to UserInfoMapperperform database operations, and UserInfoControlleris responsible for processing HTTP requests, separating business logic from database operations.

In this basic structure, it is allowed to /user/getAllobtain all user information through access. For example, run the server at this time, and then enter in the browser http://localhost:8080/user/getAllto access, you can see that all user information in the database has been obtained:

5. Add, delete, and modify operations through MyBatis

5.1 Add users

1. UserInfoMapperAdd a addUsermethod to the interface:

// 增加用户
int addUser(UserInfo user);

2. UserInfoMapper.xmlWrite the corresponding SQL statement in:

<insert id="addUser">
    insert into userinfo(username, password) values (#{username}, #{password})
</insert>

3. At this point, you can addUserunit test the

UserInfoMapper1) Right-click on the interface first , and then select Generate:

2) Select one of them Test:

3) Create a unit test class


Select Add Test addUserMethod here. After the addition is complete, you can testfind the corresponding test class in the directory:


4) Write test code


Simple explanation:

  • In the test code, @SpringBootTestannotations are used to indicate that this is a Spring Boot test.
  • @AutowiredThe annotation is used for automatic injection UserInfoMapper, allowing it to be used in tests.
  • @TransactionalAnnotations are used to represent transactional operations during the test, which will be rolled back at the end of the test to avoid actual impact on the database.

Run the test code and find that it passes the test, indicating that the code just now is correct:

5.2 Modify user

For example, you need to idmodify the user name through the user at this time:

1. UserInfoMapperAdd a updateUserByIdmethod to the interface:

// 根据id修改用户名
int updateUserById(Integer id, String username);

2. UserInfoMapper.xmlWrite the corresponding SQL statement in:

<update id="updateUserById">
    update userinfo set username=#{username} where id=#{id}
</update>

3. Run unit tests:

1) Add test method

@Test
void updateUserById() {
    
    
}

2) Write test code

At this time, userinfothe content in the table is:

It is required to idchange the user name whose is 1 to admin:

@Test
void updateUserById() {
    
    
    Integer id = 1;
    String username = "admin";
    int res = userInfoMapper.updateUserById(id, username);
    System.out.println("影响行数:" + res);
}

3) Run the test method

Execution successful:

Check the table again userinfoand find that the modification has been successfully performed:

5.3 Delete user

Now, ask to iddelete the specified user by user:

1. UserInfoMapperAdd a deleteUserByIdmethod to the interface:

// 根据 id 删除用户
int deleteUserById(Integer id);

2. UserInfoMapper.xmlWrite the corresponding SQL statement in:

<delete id="deleteUserById">
    delete from userinfo where id=#{id}
</delete>

3. Run unit tests:

1) Add test method

@Test
void deleteUserById() {
    
    
}

2) Write the test method

To delete idthe user whose is 12 at this time:

    @Test
    void deleteUserById() {
    
    
        Integer id = 12;
        int res = userInfoMapper.deleteUserById(id);
        System.out.println("影响行数:" + res);
    }

3) Run the test code

Test passed:

userinfoIt is found that the user with 12 in the table idis deleted at this time :

6. Realize query operation through MyBatis

6.1 Single table query

6.1.1 Query by user ID

1. UserInfoMapperAdd getUserByIda method to the interface:

// 根据id查询用户
UserInfo getUserById(Integer id);

2. UserInfoMapper.xmlWrite the corresponding SQL in:

Use #{}parameter placeholders:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id=#{id}
</select>

Use ${}parameter placeholders:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id=${id}
</select>

3) Run unit tests

Query idfor users with 1:

@Test
void getUserById() {
    
    
    UserInfo user = userInfoMapper.getUserById(1);
    System.out.println(user);
}

Run results using #{}parameter placeholders:

The result of using ${}the parameter placeholder:

It is not difficult to find through the above test code:

  • When using #{}the parameter placeholder, the parameter position in the SQL statement to be executed is ?, that is, it has been precompiled by SQL, and it needs to be ?assigned later;
  • When using ${}the parameter placeholder, the parameter is directly replaced.

6.1.2 Parameter placeholders #{} and ${}

In MyBatis, #{}and ${}are two commonly used parameter placeholders for referencing parameter values ​​in SQL statements. Although they look similar, there are some important differences when used.

1. #{}Placeholders:

  • #{}When the placeholder is used in the SQL statement, it will 自动进行预编译,防止 SQL 注入攻击and can handle the type conversion of the parameter. It works with most SQL parameters like strings, numbers, etc.

2. ${}Placeholders:

  • ${}Placeholders are used when used in SQL statements 将参数值直接嵌入到 SQL 语句中,不进行预编译. This can pose a SQL injection risk and needs to be used with caution. It is suitable for some special scenarios, such as dynamic table names or column names, etc.

#{}Therefore, it is recommended to use placeholders as much as possible in most cases to ensure the safety and maintainability of SQL. ${}Use placeholders only when necessary , while ensuring the legality and safety of input parameters.

6.1.3 SQL Injection Issues

${}The following SQL injection problem occurs when using simulated login:

1. UserInfoMapperAdd getUserByIda method to the interface:

// 实现登录操作
UserInfo login(UserInfo user);

2. UserInfoMapper.xmlWrite the corresponding SQL in:

<select id="login" resultType="com.example.demo.entity.UserInfo">
	select * from userinfo where username='${username}' and password='${password}'
</select>

Since the use ${}is a direct parameter replacement, it needs to ${}be added outside ''.

3. Write unit tests

First a normal demo:

@Test
void login(){
    
    
    String username = "zhangsan";
    String password = "123456";
    UserInfo user = new UserInfo();
    user.setUsername(username);
    user.setPassword(password);
    UserInfo loginUser = userInfoMapper.login(user);
    System.out.println(loginUser);
}

At this point, the object can be successfully obtained:

But if you passwordchange to:

String password = "'  or 1='1";

Run the test code again:


It is found that all the content in the database has been obtained at this time, and the executed SQL statement is:

select * from userinfo where username='zhangsan' and password='' or 1='1'

That is, regardless of whether the input usernameand passwordare correct, wherethe condition is always true true, which is the risk of SQL injection.

If you ${}change to #{}:


<select id="login" resultType="com.example.demo.entity.UserInfo">
	select * from userinfo where username=#{username} and password=#{password}
</select>

Run the previous code again:

At this time, by precompiling and then obtaining parameters, the risk of SQL injection is avoided.

6.1.3 like query

Use likefuzzy query by user name:
1. UserInfoMapperAdd getListByNamea method to the interface:

// like 模糊查询
List<UserInfo> getListByName(@Param("username") String username);

2. UserInfoMapper.xmlWrite the corresponding SQL in:

Use #{}parameter placeholders:

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like '%#{username}%'
</select>

At this time, through the unit test, it is found that an error will be reported at the end:


This is because when used #{}, the resulting SQL statement is:

select * from userinfo where username like '%'ang'%'

And this is a wrong SQL statement, all will report an error, so likewhen using the query, you need to use ${}the parameter placeholder for direct replacement .

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like '%${username}%'
</select>

Run the test code again and find that it can be found successfully:


However, there is still a SQL injection problem, so it still needs to be used #{}. For this situation, you can use the built-in function of MySQL concatto solve it:

<select id="getListByName" resultMap="BaseMap">
    select *
    from userinfo
    where username like concat('%', #{
    
    username}, '%');
</select>

Among them, concatthe function is to splice strings and support variable parameters.

6.1.4 Use resultMap to solve the mismatch between entity class parameters and database table fields

Sometimes, the parameter name in the entity class in our program may not match the field name in the database table, then MyBatis cannot correctly bind the query result to the entity class object, which can be solved by using in this case Mapper XML.resultMap

For example, userinfothe password field in the table is password, and the attribute name in the entity class is called pwd. At this time, getUserByIdthe user is queried through, and finally pwdthe attribute is found to be empty:


At this point, UserInfoMapper.xmladd a new resultMaptag to the file:

Simple explanation:

  • <id>Elements: Maps that define primary keys. columnThe attribute specifies the column name of the database table, and propertythe attribute specifies the attribute name of the entity class. In this example, the primary key column "id" of the database table is mapped to the attribute "id" of the entity class.

  • <result>Element: defines the mapping of common columns. columnThe attribute specifies the column name of the database table, and propertythe attribute specifies the attribute name of the entity class. In this example, the "username" column of the database table is mapped to the attribute "username" of the entity class, the "password" column is mapped to the attribute "pwd" of the entity class, and the "photo" column is mapped to the attribute "photo" of the entity class.

Then modify getUserByIdthe SQL corresponding to the method, and modify the returned result to be a dictionary mapping baseMap:

<select id="getUserById" resultMap="baseMap">
    select * from userinfo where id=${id}
</select>

Run the test code again to get the correct result:

passwordOf course, you can also rename to in the SQL statement pwdto solve this problem, for example:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select id, username, password as pwd, photo, createtime, updatetime, state 
    from userinfo where id=${id}
</select>

At this time, the correct result can also be obtained:

6.2 Multi-table query

6.2.1 Creation of VO class

When performing representative queries, it is usually necessary to create a value object (VO, Value Object) to contain information about multiple tables. The VO class is a Java class, usually used to encapsulate the attributes of multiple entity classes, so as to facilitate the transfer and processing of data in multiple table queries.

For example, at this time, you need to query the article details through the article id, and the article details need to contain the user name, but articleInfothere are only users in the table uid, so you need to perform multi-table query. In order to facilitate the combination of user name and article information, an additional ArticleInfoVOclass needs to be created.

First create articleinfothe entity class corresponding to the table ArticleInfo:

Then inherit this class and vocreate a ArticleInfoVOclass under the directory:

6.2.2 Create Mapper interface and XML mapping file

1. Create a Mapper interface ArticleInfoVOMapper:

2. Create an XML mapping file ArticleInfoVOMapper.xml:

6.2.3 Query article details

1. ArticleInfoVOMapperCreate a method in the interface getDetial:

// 通过文章 id 查询文章详情
ArticleInfoVO getDetial(Integer id);

2. ArticleInfoVOMapper.xmlWrite the corresponding SQL statement in the file:

<select id="getDetial" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a 
        left join userinfo u on a.uid = u.id 
                           where a.id = #{id}
</select>

3. Write unit tests

@SpringBootTest
class ArticleInfoVOMapperTest {
    
    

    @Autowired
    private ArticleInfoVOMapper articleInfoVOMapper;

    @Test
    void getDetail() {
    
    
        ArticleInfoVO detail = articleInfoVOMapper.getDetail(1);
        System.out.println(detail);
    }
}

Run the test code and find that the result can be found correctly:

7. The use of MyBatis dynamic SQL

MyBatis dynamic SQL refers to the process of dynamically generating SQL queries or update statements according to different conditions and parameters . It allows dynamic assembly of various parts of SQL statements according to business needs when writing SQL mapping files, thereby achieving more flexible database operations. Dynamic SQL is very useful in dealing with different query conditions, sorting, filtering, etc. It can avoid writing a large number of repeated SQL statements due to multiple situations, thereby improving development efficiency.

MyBatis provides a series of XML tags and syntax for building dynamic SQL. These tags can be used to include operations such as conditional judgment, loop traversal, and dynamic splicing of SQL fragments. Some commonly used dynamic SQL tags include <if>, <choose>, <when>, <otherwise>, <trim>, <where>, <set>, <foreach>etc. For details, please refer to MyBatis official website: Dynamic SQL .

In short, MyBatis dynamic SQL is a powerful mechanism that makes it more flexible and convenient to generate appropriate SQL statements according to different situations in the SQL mapping file. The following is a detailed introduction to some common dynamic SQL tags.

7.1 if tag

<if>Labels are used to add conditional judgments in SQL statements, and dynamically generate SQL fragments according to the true or false conditions.

For example, when adding user information, photothe content of the field may not be entered by the user. In this case, you need to use <if>the tag to build dynamic SQL:

<insert id="addUser">
    insert into userinfo(
    username,
    <if test="photo!=null and photo!=''">
        photo,
    </if>
    password
    )
    values (
    #{username},
    <if test="photo!= null and photo!=''">
        #{photo},
    </if>
    #{pwd}
    )
</insert>

It should be noted that the attribute <if>in the tag testspecifies the attribute of the object passed in, not the field in the database table.

In the unit test, only enter usernameand password, and the final SQL only has these two fields:

if you add an photoattribute:


It can be found that there are three fields at this time.

7.2 trim label

If all the attributes entered are optional, then only using <if>the tag cannot solve ,the problem, because I don’t know ,where it will appear, it can appear in the front, or it may appear in the back. If there is no input, it may be all does not appear. Therefore, to solve this problem, tags need to be introduced <trim>.

<trim>Label properties:

  • prefix: Represents the entire statement block, prefixprefixed with the value of
  • suffix: Indicates the entire statement block, suffixsuffixed with the value of
  • prefixOverrides: Indicates the prefix to be removed from the entire statement block
  • suffixOverrides: Indicates the suffix to be removed from the entire statement block

usernameFor example, the three fields , password, and photoare optional when adding users :

<insert id="addUser">
    insert into userinfo
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="username!=null and username!=''">
            username,
        </if>
        <if test="photo!=null and photo!=''">
            photo,
        </if>
        <if test="pwd!=null and pwd!=''">
            password,
        </if>
    </trim>
    values
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="username!=null and username!=''">
            #{username},
        </if>
        <if test="photo!=null and photo!=''">
            #{photo},
        </if>
        <if test="pwd!=null and pwd!=''">
            #{pwd},
        </if>
    </trim>
</insert>

Among them, <trim>the role of the label is to trim the inserted column name and value part, and redundant commas can be deleted at the beginning and end positions. prefixAttributes represent what is added before the SQL fragment, suffixattributes represent what is added after the SQL fragment, and suffixOverridesattributes represent what is removed at the end of the SQL fragment.

7.3 where tag

<where>Labels are used to add conditions to the WHERE clause of an SQL statement and handle the logic between the conditions.

For example, you can now query through idthe or of the article, where the content of and are optional inputs, and fuzzy matching is used.titleidtitletitle

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a
    left join userinfo u on a.uid = u.id
    <where>
        <if test="id != null and id > 0">
            and a.id = #{
    
    id}
        </if>

        <if test="title!=null and title!=null">
            and a.title like concat('%', #{
    
    title}, '%')
        </if>
    </where>
</select>

In addition, <where>the label will automatically remove the prefix and.

Of course, you can also use <trim>the and <if>tags to achieve this functionality:

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a
    left join userinfo u on a.uid = u.id
    <trim prefix="where" prefixOverrides="and">
        <if test="id != null and id > 0">
            and a.id = #{
    
    id}
        </if>

        <if test="title!=null and title!=null">
            and a.title like concat('%', #{
    
    title}, '%')
        </if>
    </trim>
</select>

At this time, you need to use <trim>tags to remove a prefix andand add a prefix where.

7.4 set tags

<set>Labels are used to set the fields that need to be updated in the update statement, and dynamically generate the update statement according to the conditions.

For example, idto modify nullthe attributes of the user who is not by the user:

<update id="updateById">
    update userinfo
    <set>
        <if test="username!=null and username!=''">
            username=#{
    
    username},
        </if>

        <if test="pwd!=null and pwd!=''">
            password=#{
    
    pwd},
        </if>

        <if test="photo!=null and photo!=''">
            photo=#{
    
    photo},
        </if>
    </set>
    where id=#{
    
    id}
</update>

<set>tags and <where>instead, it only strips the suffixed ones ,.

7.5 foreach tag

<foreach>Labels are used to iterate through a collection or array and add its elements to an SQL statement.

<foreach>Tags have the following attributes:

  • collection: The collection in the binding method parameter, such as List, Set, Map or array object
  • item: each object when traversing
  • open: The string at the beginning of the statement block
  • close: The string at the end of the statement block
  • separator: A string of intervals between each traversal

For example, now you need to iddelete the corresponding article based on multiple articles:

1. ArticleInfoVOMapperAdd a method to the interface:

// 根据多个文章 `id`来删除对应的文章
int deleteByIds(List<Integer> ids);

2. When ArticleInfoVOMapper.xmlwriting the corresponding SQL:

<delete id="deleteByIds">
    delete from articleinfo where id in
    <foreach collection="ids" item="item" open="(" close=")" separator=",">
        #{item}
    </foreach>
</delete>

This code demonstrates an example of building a delete statement using MyBatis' dynamic SQL. DELETEThis delete statement will dynamically generate the clause in the statement according to the given ID list IN, so as to delete records satisfying the condition in batches.

Simple explanation:

  1. <delete>Label: This label represents the definition of a delete statement.

  2. <foreach>Label: This label is used to traverse the collection and add the elements in the collection to the SQL statement. In this example, it would idsadd each element in the collection to INthe clause, forming (id1, id2, id3)a structure like .

    • collectionAttribute: Specifies the collection to traverse.
    • itemAttribute: Specifies the alias of each element during traversal.
    • openAttribute: Specify the character at the beginning of the traversal, here it is (.
    • closeAttribute: Specifies the character at the end of the traversal, here it is ).
    • separatorAttribute: Specifies the separator between elements, here is a comma ,.

In this way, dynamic SQL can be used to build bulk delete statements to delete corresponding records based on a given set of IDs.

3. Run unit tests:

@Transactional
@Test
void deleteByIds() {
    
    
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    ids.add(4);
    int res = articleInfoVOMapper.deleteByIds(ids);
    System.out.println("影响行数:" + res);
}

Test passed:

Guess you like

Origin blog.csdn.net/qq_61635026/article/details/132172986