In daily development, you should be able to find that the CRUD function code of a single table is highly repetitive and not difficult. This part of the code is often relatively large and time-consuming to develop.
Therefore, some components are currently used in enterprises to simplify or omit the CRUD development work of a single table. One component that is currently used more in China is MybatisPlus.
The official website is as follows:
Of course, MybatisPlus not only simplifies single-table operations, but also has many enhancements to the functions of Mybatis. It can make our development simpler and more efficient.
Through today's study, we will achieve the following goals:
-
Can use MybatisPlus to implement basic CRUD
-
Will use conditional construction to build queries and update statements
-
Will use common annotations in MybatisPlus
-
Will use MybatisPlus to process enumeration and JSON type fields
-
Will use MybatisPlus to implement paging
In order to facilitate testing, we first create a new project and prepare some basic data.
1.Environment preparation
Copy a project provided in the pre-course material to your workspace (do not include spaces or special characters):
Then open it with your IDEA tool. The project structure is as follows:
Pay attention to configuring the JDK version of the project to JDK11. First click on the project structure settings:
Configure JDK in the pop-up window:
Next, we need to import two tables. The SQL files have been provided in the pre-class materials:
The corresponding database table structure is as follows:
Finally, application.yaml
modify the jdbc parameters in to your own database parameters:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: MySQL123
logging:
level:
com.itheima: debug
pattern:
dateformat: HH:mm:ss
2. Quick start
For example, if we want to implement CRUD for the User table, we only need the following steps:
-
Introduce MybatisPlus dependency
-
Define Mapper
2.1Introduce dependencies
MybatisPlus provides a starter to realize the automatic assembly function of automatic Mybatis and MybatisPlus. The coordinates are as follows:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
Since this starter contains automatic assembly of mybatis, it can completely replace the Mybatis starter. Ultimately, the project’s dependencies are as follows:
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.2 Define Mapper
In order to simplify single-table CRUD, MybatisPlus provides a basic BaseMapper
interface, which has already implemented single-table CRUD:
Therefore, as long as our custom Mapper implements this BaseMapper
, there is no need to implement single-table CRUD ourselves. Modify the interface com.itheima.mp.mapper
under the package in mp-demo UserMapper
and let it inherit BaseMapper
:
code show as below:
package com.itheima.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
public interface UserMapper extends BaseMapper<User> {
}
2.3 Testing
Create a new test class, write several unit tests, and test basic CRUD functions:
package com.itheima.mp.mapper;
import com.itheima.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
User user = new User();
user.setId(5L);
user.setUsername("Lucy");
user.setPassword("123");
user.setPhone("18688990011");
user.setBalance(200);
user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userMapper.insert(user);
}
@Test
void testSelectById() {
User user = userMapper.selectById(5L);
System.out.println("user = " + user);
}
@Test
void testSelectByIds() {
List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L, 5L));
users.forEach(System.out::println);
}
@Test
void testUpdateById() {
User user = new User();
user.setId(5L);
user.setBalance(20000);
userMapper.updateById(user);
}
@Test
void testDelete() {
userMapper.deleteById(5L);
}
}
As you can see, the SQL log printed during the running process is very standard:
11:05:01 INFO 15524 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
11:05:02 INFO 15524 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
11:05:02 DEBUG 15524 --- [ main] c.i.mp.mapper.UserMapper.selectById : ==> Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM user WHERE id=?
11:05:02 DEBUG 15524 --- [ main] c.i.mp.mapper.UserMapper.selectById : ==> Parameters: 5(Long)
11:05:02 DEBUG 15524 --- [ main] c.i.mp.mapper.UserMapper.selectById : <== Total: 1
user = User(id=5, username=Lucy, password=123, phone=18688990011, info={"age": 21}, status=1, balance=20000, createTime=Fri Jun 30 11:02:30 CST 2023, updateTime=Fri Jun 30 11:02:30 CST 2023)
3. Common annotations
In the introductory case just now, we only introduced dependencies, and inherited BaseMapper to be able to use MybatisPlus, which is very simple. But here comes the question: How does MybatisPlus know which table we want to query? What fields are there in the table?
Recall that UserMapper specified a generic when inheriting BaseMapper:
The User in the generic type is the PO corresponding to the database.
MybatisPlus infers table information based on PO entity information to generate SQL. by default:
-
MybatisPlus will convert the class name of the PO entity to camel case and underline it as the table name.
-
MybatisPlus will convert all variable names of the PO entity to camel case and underline them as the field names of the table, and infer the field type based on the variable type.
-
MybatisPlus will use the field named id as the primary key
But in many cases, the default implementation does not match the actual scenario, so MybatisPlus provides some annotations to facilitate us to declare table information.
3.1@TableName
illustrate:
-
Description: Table name annotation, identifying the table corresponding to the entity class
-
Where to use: Entity class
Example:
@TableName("user")
public class User {
private Long id;
private String name;
}
In addition to specifying the table name, the TableName annotation can also specify many other attributes:
Attributes |
type |
Must be specified |
default value |
describe |
value |
String |
no |
"" |
Table Name |
schema |
String |
no |
"" |
schema |
keepGlobalPrefix |
boolean |
no |
false |
Whether to keep using the global tablePrefix value (when the global tablePrefix is in effect) |
resultMap |
String |
no |
"" |
The id of resultMap in xml (used to satisfy specific types of entity class object binding) |
autoResultMap |
boolean |
no |
false |
Whether to automatically build and use resultMap (if resultMap is set, automatic construction and injection of resultMap will not be performed) |
excludeProperty |
String[] |
no |
{} |
Attribute names that need to be excluded@since 3.3.1 |
3.2@TableId
illustrate:
-
Description: Primary key annotation, identifying the primary key field in the entity class
-
Where to use: Primary key field of entity class
Example:
@TableName("user")
public class User {
@TableId
private Long id;
private String name;
}
TableId
Annotations support two properties:
Attributes |
type |
Must be specified |
default value |
describe |
---|---|---|---|---|
value |
String |
no |
"" |
Table Name |
type |
Enum |
no |
IdType.NONE |
Specify primary key type |
IdType
Supported types are:
value |
describe |
---|---|
AUTO |
Database ID auto-increment |
NONE |
Stateless, this type has no primary key set (the annotation is equivalent to following the global, and the global Rio is approximately equal to INPUT) |
INPUT |
Set the primary key value before inserting |
ASSIGN_ID |
Assign ID (primary key type is Number (Long and Integer) or String) (since 3.3.0), use the method nextId of the interface IdentifierGenerator (the default implementation class is DefaultIdentifierGenerator snowflake algorithm) |
ASSIGN_UUID |
Assign UUID, the primary key type is String (since 3.3.0), use the method nextUUID of the interface IdentifierGenerator (default method) |
|
Distributed globally unique ID long integer type (please use ASSIGN_ID) |
|
32-bit UUID string (please use ASSIGN_UUID) |
|
Distributed globally unique ID string type (please use ASSIGN_ID) |
There are three common ones here:
-
AUTO
: Use the database id to grow automatically -
INPUT
: Manually generate id -
ASSIGN_ID
: The snowflake algorithm generatesLong
a globally unique id for the type. This is the default ID strategy.
3.3@TableField
illustrate:
Description: Common field annotations
Example:
@TableName("user")
public class User {
@TableId
private Long id;
private String name;
private Integer age;
@TableField("isMarried")
private Boolean isMarried;
@TableField("concat")
private String concat;
}
Generally, we do not need to add @TableField
annotations to fields, except for some special circumstances:
-
The member variable name is inconsistent with the database field name
-
Member variables are
isXXX
named after, and according toJavaBean
the specification,MybatisPlus
they will be removed when identifying fieldsis
, which results in inconsistency with the database. -
The member variable name is consistent with the database, but conflicts with the keyword of the database. Use
@TableField
annotations to add ```` escapes to field names
Other supported attributes are as follows:
Attributes |
type |
Required |
default value |
describe |
value |
String |
no |
"" |
Database field name |
exist |
boolean |
no |
true |
Whether it is a database table field |
condition |
String |
no |
"" |
Field where entity query comparison condition. If there is a value set, the set value shall prevail. If not, the default global %s=#{%s} will be used. Please refer to (opens new window) |
update |
String |
no |
"" |
Field update set is partially injected. For example: when annotating update="%s+1" on the version field indicates that it will set version=version+1 when updating (this attribute has a higher priority than the el attribute) |
insertStrategy |
Enum |
no |
FieldStrategy.DEFAULT |
举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>) |
updateStrategy |
Enum |
no |
FieldStrategy.DEFAULT |
举例:IGNORED update table_a set column=#{columnProperty} |
whereStrategy |
Enum |
no |
FieldStrategy.DEFAULT |
举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if> |
fill |
Enum |
no |
FieldFill.DEFAULT |
Field autofill strategy |
select |
boolean |
no |
true |
Whether to perform select query |
keepGlobalFormat |
boolean |
no |
false |
Whether to keep using the global format for processing |
jdbcType |
JdbcType |
no |
JdbcType.UNDEFINED |
JDBC type (this default value does not mean that it will take effect according to this value) |
typeHandler |
TypeHander |
no |
Type processor (this default value does not mean that it will take effect according to this value) |
|
numericScale |
String |
no |
"" |
Specify the number of digits to retain after the decimal point |
4. Common configurations
MybatisPlus also supports custom configuration based on yaml files. Please see the official documentation for details:
Most configurations have default values, so we don't need to configure them. But there are also some that have no default value, such as:
-
Alias scanning package for entity classes
-
global id type
mybatis-plus:
type-aliases-package: com.itheima.mp.domain.po
global-config:
db-config:
id-type: auto # 全局id类型为自增长
It should be noted that MyBatisPlus also supports handwritten SQL, and the reading address of the mapper file can be configured by yourself:
mybatis-plus:
mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。
You can see that the default value is classpath*:/mapper/**/*.xml
, which means that as long as we place the mapper.xml file in this directory, it will be loaded.
For example, let's create a new UserMapper.xml
file:
Then define a method in it:
<?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.itheima.mp.mapper.UserMapper">
<select id="queryById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
Then UserMapperTest
test the method in the test class:
@Test
void testQuery() {
User user = userMapper.queryById(1L);
System.out.println("user = " + user);
}