参考代码demo6

MyBatis-Plus

相关资源:

简单开始

数据准备

创建数据库及表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DROP DATABASE IF EXISTS `mybatis_plus`;

CREATE DATABASE `mybatis_plus`;

use `mybatis_plus`;

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
id BIGINT NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);

添加数据

1
2
3
4
5
6
7
8
DELETE FROM `user`;

INSERT INTO `user` (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

初始化工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.liangjiajia.cs</groupId>
<artifactId>demo6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo6</name>
<description>demo6</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.21</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

重点:pom.xmlspring-boot-starter-parent-3.2.2.pomspring-boot-dependencies-3.2.2.pom\text {pom.xml} \rightarrow \text {spring-boot-starter-parent-3.2.2.pom} \rightarrow \text {spring-boot-dependencies-3.2.2.pom}

  • Lombok\text {Lombok}:默认版本1.18.30

  • MySQL Connector Java\text {MySQL Connector Java}:默认版本8.3.0

  • MyBatis Plus Spring Boot Starter\text {MyBatis Plus Spring Boot Starter}:指定版本3.5.5

  • Druid Spring Boot Starter\text {Druid Spring Boot Starter}:指定版本1.2.21

配置

1
2
3
4
5
6
7
8
9
10
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

编码

com.liangjiajia.cs.pojo.User\text {com.liangjiajia.cs.pojo.User}

1
2
3
4
5
6
7
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}

com.liangjiajia.cs.Mapper.UserMapper\text {com.liangjiajia.cs.Mapper.UserMapper}

1
2
3
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

com.liangjiajia.cs.Application\text {com.liangjiajia.cs.Application}

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@MapperScan("com.liangjiajia.cs.mapper")
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

测试

1
2
3
4
5
6
7
@Test
public void testSelectAll() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.isTrue(5 == userList.size(), "");
userList.forEach(System.out::println);
}

BaseMapper

BaseMapper:insert

1
2
// 插入一条记录
int insert(T entity);
类型 参数名 描述
T entity 实体对象
1
2
3
4
5
6
7
8
9
@Test
public void testInsert(){
User user = new User();
user.setName("James");
user.setAge(30);
user.setEmail("test6@baomidou.com");
int result = userMapper.insert(user);
System.out.println("Insert result: " + result);
}

为了后续实验,连续测试 44 次,此时的数据库表:

BaseMapper:delete

1
2
3
4
5
6
7
8
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据 ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
1
2
3
4
5
6
7
@Test
public void testDelete() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "Billie");
int result = userMapper.delete(wrapper);
System.out.println("Delete result: " + result);
}
1
2
3
4
5
6
@Test
public void testDeleteBatchIds() {
List<Long> ids= Arrays.asList(1760553433684344833L, 1760554075639291906L);
int result = userMapper.deleteBatchIds(ids);
System.out.println("Delete Batch Ids result: " + result);
}
1
2
3
4
5
@Test
public void testDeleteById() {
int result = userMapper.deleteById(1760554103854411778L);
System.out.println("Delete by Id result: " + result);
}
1
2
3
4
5
6
7
@Test
public void testDeleteByMap() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("name", "James");
int result = userMapper.deleteByMap(columnMap);
System.out.println("Delete by Map result: " + result);
}

BaseMapper:update

1
2
3
4
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
1
2
3
4
5
6
7
8
@Test
public void testUpdate() {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("name", "Sandy")
.set("email", "Sandy@example.com");
int result = userMapper.update(null, wrapper);
System.out.println("Update result: " + result);
}
1
2
3
4
5
6
7
8
@Test
public void testUpdateById() {
User user = new User();
user.setId(4L);
user.setEmail("sandy@example.com");
int result = userMapper.updateById(user);
System.out.println("Update by Id result: " + result);
}

BaseMapper:select

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

自定义方法

application.yml\text {application.yml} 配置 mybatis-plus.mapper-locations:\text {mybatis-plus.mapper-locations:}

默认值(classpath*: /mapper/**/* . xml\text {classpath*: /mapper/**/* . xml}

Service

MyBatis Plus\text {MyBatis Plus} 中,Service CRUD\text {Service CRUD} 接口指IService<T>接口及其实现ServiceImpl<M, T>,提供了一套丰富的 CRUD\text {CRUD}(创建、读取、更新、删除)操作。这些接口旨在进一步简化数据库操作,使开发者能够更加专注于业务逻辑而非底层数据库访问细节。

com.liangjiajia.cs.service.UserService\text {com.liangjiajia.cs.service.UserService}

1
2
public interface UserService extends IService<User> {
}

com.liangjiajia.cs.service.impl.UserServiceImpl\text {com.liangjiajia.cs.service.impl.UserServiceImpl}

1
2
3
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

具体使用查看官方文档!

常用注解

  • @TableName:指定实体类对应的数据库表名。
    • @TableName("t_user")
  • @TableId:标记一个字段为表的主键字段,并可指定主键生成策略。
    • @TableId(value = "id", type = IdType.AUTO)
  • @TableField:指定属性对应的数据库列名。可用于处理 Java\text {Java}属性和数据库列名不一致的情况,或者指定字段的填充策略。
    • @TableField("user_name")
  • @TableLogic:标记逻辑删除属性。逻辑删除是指用某个字段的值来表示删除状态,而不是真的从数据库中删除记录。

条件构造器

QueryWrapper是用于构建查询条件的。它提供了丰富的方法来构建几乎所有类型的 SQL\text {SQL} 查询条件,包括等于、不等于、大于、小于、LIKE\text {LIKE}BETWEEN\text {BETWEEN}IS NUL\text {IS NUL} 等,还支持链式调用,使得构建复杂查询条件变得简单。

1
2
3
4
5
6
7
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq("name", "John Doe")
.between("age", 18, 30)
.isNotNull("email");

List<User> users = userMapper.selectList(queryWrapper);

UpdateWrapperQueryWrapper类似,但专门用于构建更新操作的条件。它允许在更新语句中设置哪些字段需要更新以及更新的条件。

1
2
3
4
5
6
7
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper
.set("email", "john.doe@example.com")
.eq("name", "John Doe")
.gt("age", 18);

int updateCount = userMapper.update(null, updateWrapper);

为了避免硬编码字段字符串,MyBatis-Plus\text {MyBatis-Plus} 还提供了LambdaQueryWrapperLambdaUpdateWrapper,它们允许通过 Java 8\text {Java 8}Lambda\text {Lambda} 表达式来引用实体类的属性,从而避免因字段名错误而导致的运行时异常。

1
2
3
4
5
6
7
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
lambdaQuery
.eq(User::getName, "John Doe")
.between(User::getAge, 18, 30)
.isNotNull(User::getEmail);

List<User> users = userMapper.selectList(lambdaQuery);
1
2
3
4
5
6
7
LambdaUpdateWrapper<User> lambdaUpdate = new LambdaUpdateWrapper<>();
lambdaUpdate
.set(User::getEmail, "john.doe@example.com")
.eq(User::getName, "John Doe")
.gt(User::getAge, 18);

int updateCount = userMapper.update(null, lambdaUpdate);

插件

分页插件

MyBatis-Plus\text {MyBatis-Plus} 的分页插件是一个用于简化分页操作的强大工具,它允许开发者轻松实现分页查询而无需编写繁琐的分页逻辑代码。这个插件通过拦截 MyBatis\text {MyBatis} 执行的 SQL\text {SQL} 语句,自动添加分页的 SQL\text {SQL} 语句,如 LIMIT(在 MySQL\text {MySQL} 中)。

com.liangjiajia.cs.config.MybatisPlusConfig\text {com.liangjiajia.cs.config.MybatisPlusConfig}

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@MapperScan("com.liangjiajia.cs.mapper")
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

乐观锁 && 悲观锁

com.liangjiajia.cs.config.MybatisPlusConfig\text {com.liangjiajia.cs.config.MybatisPlusConfig}

增加一行:interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

其他可以查看手册…