MyBatisPlus入门

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

JPA

Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA based repositories. This module deals with enhanced support for JPA based data access layers. It makes it easier to build Spring-powered applications that use data access technologies.

Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that’s actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

Features

  • Sophisticated support to build repositories based on Spring and JPA
  • Support for Querydsl predicates and thus type-safe JPA queries
  • Transparent auditing of domain class
  • Pagination support, dynamic query execution, ability to integrate custom data access code
  • Validation of @Query annotated queries at bootstrap time
  • Support for XML based entity mapping
  • JavaConfig based repository configuration by introducing @EnableJpaRepositories.

MybatisPlus

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

框架结构


快速入门

1.创建对应数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DROP TABLE IF EXISTS user;

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

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');

2.初始化项目(SpringBoot)

添加依赖

  • 引入 Spring Boot Starter 父工程:
1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/>
</parent>
  • 引入 spring-boot-starterspring-boot-starter-testmybatis-plus-boot-starterh2依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

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
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
  • 配置连接数据库
1
2
3
4
5
# application.properties
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimeZone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  • 创建实体类pojo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.zero.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
  • 编写Mapper接口
1
2
3
4
5
6
7
8
9
10
11
package com.zero.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zero.pojo.User;
import org.springframework.stereotype.Repository;

@Mapper /* @Mapper注解由Mybatis框架定义的一个描述数据层接口的注解,用于告诉sprigng此接口的实现类由Mybatis负责创建,并将其实现类对象存储到spring容器中 */
@Repository /*持久层*/
public interface UserMapper extends BaseMapper<User> { /*继承基本的类BaseMapper*/

}
  • 启动类扫描(使用@Mapper无需该步骤)
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.zero;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.zero.mapper") /* 扫描mapper文件夹*/
@SpringBootApplication
public class MybatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusDemoApplication.class, args);
}
}
  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zero;

import com.zero.mapper.UserMapper;
import com.zero.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class MybatisPlusDemoApplicationTests {
@Autowired
private UserMapper userMapper;

@Test
void contextLoads() {
/*参数:wrapper 条件构造器 */
/*查询全部用户*/
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}

配置日志

1
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl 

主键生成策略

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void insertTest(){
User user = new User();

user.setName("Kate");
user.setAge(11);
user.setEmail("2323256@qq.com");
int result = userMapper.insert(user);
System.out.println(result);
/*未设置id,但MybatisPlus自动生成id*/
System.out.println(user);
}

分布式系统唯一ID生成方案汇总


1.数据库自增长序列或字段

最常见的方式,全数据库唯一。

优点:

  • 简单

  • 数字ID天然排序,便于分页或者排序

缺点:

  • 不同数据库语法和实现不同,数据库迁移或多数据库版本支持时需要处理

  • 在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险

  • 不适用于高并发环境

  • 并非一定连续,如MySQL中当生成新ID的事务回滚,那么后续的事务不会再用该ID。为了保证连续,必须在事务结束后才能生成ID,影响性能


2.UUID

通用唯一识别码Universally Unique Identifier)是用于计算机体系中以识别信息的一个128位标识符。根据标准方法生成,不依赖中央机构的注册和分配,UUID具有唯一性,这与其他大多数编号方案不同。重复UUID码概率接近零,可以忽略不计。

可以利用数据库也可以利用程序生成。UUID是由32个的16进制数字组成,所以每个UUID的长度是128位。

UUID 通常用作唯一键的数据库表。MySQL 提供了一个 UUID 函数,它生成标准版本1 UUID(日期时间和MAC地址)。当 UUID 用作主键时,版本3、4和5 UUID 的随机性以及版本1和2 UUID 内的字段的排序可能会产生数据库位置或性能问题。

优点:

  • 简单,代码方便

  • 生成ID性能非常好

  • 可应对数据迁移,系统数据合并,或者数据库变更的情况

缺点:

  • 没有排序,无法保证递增

  • 往往使用字符串存储,查询效率较低

  • 需要存储空间比较大

  • 传输数据量大

  • 不可读(UUID to Int64


3.Redis生成ID

当使用数据库生成ID性能不够,可以尝试使用Redis生成ID。主要依赖于Redis是单线程的,可以生成全局唯一的ID。使用用Redis的原子操作INCR和INCRBY来实现。

优点:

  • 不依赖于数据库,灵活方便,且性能优于数据库。

  • 数字ID天然排序,便于分页或者排序。

缺点:

  • 需要引入Redis,增加系统复杂度。

  • 需要编码和配置


4.snowflake 雪花算法

snowflake是Twitter开源的分布式ID生成算法,结果为long型的ID。

使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号,最后还有一个永远是0的符号位。

优点:

  • 不依赖于数据库,灵活方便,且性能优于数据库

  • ID按照时间在单机上是递增的

缺点:

  • 分布式环境下需要解决时间回拨问题

1
2
3
4
5
6
7
8
9
public enum IdType {
AUTO(0), /*数据库ID自增*/
NONE(1), /*未设置主键类型*/
INPUT(2), /*用户输入ID*/
/* 只有当插入对象ID为空自动填充 */
ID_WORKER(3), /*全局唯一ID (idWorker)[默认策略]*/
UUID(4), /*全局唯一ID (UUID)*/
ID_WORKER_STR(5); /*字符串全局唯一ID (ID_WORKER的字符串表示)*/
}

1.实体字段上加上@TableID

1
2
@TableId(type= IdType.AUTO)
private Long id;

2.数据库字段设置为对应类型(如自增)

sqlyog->对应数据库和表->改变表



CRUD

  • Update
1
2
3
4
5
6
7
8
9
10
@Test
public void updateTest(){
User user = new User();
user.setId(1L);
user.setName("K");
user.setAge(21);
user.setEmail("230000@qq.com");
int result = userMapper.updateById(user); /*参数对象*/
System.out.println(result);
}
  • Select
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void selectByIdTest(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
/*批量查询*/
@Test
public void selectByBatchID(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
users.forEach(System.out::println);
}
/*条件查询*/
@Test
public void selectByBatchIdsTest(){
HashMap<String,Object> map = new HashMap<>();
map.put("name","Zus");
map.put("age",13);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
  • delete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void deleteByIdTest(){
int result = userMapper.deleteById(8L);
System.out.println(result);
}
/*批量删除*/
@Test
public void deleteByBatchTest(){
int result = userMapper.deleteBatchIds(Arrays.asList(6L,7L));
}
@Test
public void deleteByMapTest(){
HashMap<String,Object> map = new HashMap<>();
map.put("name","Yi");
int result = userMapper.deleteByMap(map);
}

自动填充

1.数据库级别(不推荐)

  • 在表中新增字段create_time、update_time
  • 实体类同步
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type= IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
private Date createTime;
private Date updateTime;
}

2.代码级别

MyBatis-Plus 3.0.5

  • 在表中新增字段create_time、update_time
  • 实体类字段属性上增加注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type= IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
  • 编写处理器处理该注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.zero.handler;

@Slf4j
@Component /*注册组件,将处理器加到Ioc容器中*/
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}

@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}

MyBatis-Plus 3.3.0(官方)

1
2
3
4
5
6
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type= IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}

@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}


乐观锁与悲观锁

在关系数据库管理系统里,乐观并发控制(乐观锁,Optimistic Concurrency Control,OCC)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。

乐观并发控制多数用于数据争用不大、冲突较少的环境中,这种环境中,偶尔回滚事务的成本会低于读取数据时锁定数据的成本,因此可以获得比其他并发控制方法更高的吞吐量。

乐观并发控制的事务包括以下阶段:

  • 读取:事务将数据读入缓存,这时系统会给事务分派一个时间戳。
  • 校验:事务执行完毕后,进行提交。这时同步校验所有事务,如果事务所读取的数据在读取之后又被其他事务修改,则产生冲突,事务被中断回滚。
  • 写入:通过校验阶段后,将更新的数据写入数据库。

在关系数据库管理系统里,悲观并发控制悲观锁,Pessimistic Concurrency Control,PCC)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作读某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。

悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。


Optimistic vs Pessimistic locking

Lost Update anomaly:

由于Bob改变了账号余额,Alice并不能提到40(Alice查询账号count余额大于40故发起提款请求,Alice查询和取款工程中Bob实际已经完成了查询和取款操作)

  • Pessimistic Locking

悲观锁通过对帐户采取共享或读取锁从而防止 Bob 更改帐户。

只有Alice提交她的事务并释放读锁定之后,Bob 才会恢复并应用更改。在 Alice 释放读取锁之前,Bob 的 UPDATE 会阻塞。

  • Optimistic Locking

乐观锁定允许发生冲突,但在version更改时,来自 Alice 的 UPDATE 操作时会检测到冲突。

每次执行 UPDATE 或 DELETE 时,version列都会递增,用于 UPDATE 和 DELETE 语句的 WHERE 子句中,需要在执行 UPDATE 或 DELETE 之前发出 SELECT 并读取当前值。


OptimisticLockerInnerInterceptor

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion(确保查询到修改过程中没有其他人进行修改,即当要更新一条记录的时候,希望这条记录没有被别人更新)
  • 如果 version 不对,就更新失败

1.数据库添加version字段

2.实体类添加对应字段

1
2
@Version
private Integer version;

3.配置插件

Mybatis-Plus 3.0.5

1
2
3
4
5
6
7
8
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}

Mybatis-Plus 3.5.1

1
2
3
4
5
6
7
8
9
10
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}

4.测试

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
@Test
public void optimisticLockerTest(){
/*查询用户*/
User user = userMapper.selectById(1L);
/*修改用户对应字段*/
user.setName("adc");
user.setEmail("df@qq.com");
/*执行更新操作*/
userMapper.updateById(user);
}

@Test
public void optimisticLockerTest2(){
User user = userMapper.selectById(1L);
user.setName("Aone");
user.setEmail("Aone@qq.com");

/*模拟插队*/
User user2 = userMapper.selectById(1L);
user2.setName("Bone");
user2.setEmail("Bone@qq.com");
userMapper.updateById(user2);

userMapper.updateById(user);
}

分页

Mybatis-plus 3.0.5

1.配置分页插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@MapperScan("com.zero.mapper")
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}

@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}

2.测试

1
2
3
4
5
6
7
8
9

@Test
public void limitPageTest(){
/*当前页 页大小*/
Page<User> page = new Page<>(2,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}

逻辑删除

逻辑删除(logical deletion),又被称软删除假删除,是一种数据库操作,使用标记将数据标为不可用,而不从数据库删除数据本身。使用适当的方法可恢复被删除的文件。

1.数据库中增加字段

2.实体类增加字段

1
2
@TableLogic
private Integer deleted;

Mybatis-plus 3.0.5

3.配置插件

1
2
3
4
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
1
2
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4.测试

1
2
3
4
5
@Test
public void deleteByIdTest(){
int result = userMapper.deleteById(1L);
System.out.println(result);
}

性能分析器

性能分析拦截器,用于输出每条SQL语句及其执行时间

Mybatis-plus3.0.5

1。配置插件

1
2
3
4
5
6
7
8
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1000); /*设置sql最长执行时间*/
performanceInterceptor.setFormat(true); /*格式化代码*/
return performanceInterceptor;
}
1
spring.profiles.active=dev

2.测试


条件构造器(Wrapper)

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
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;

@Test
void wrapperTest1() {
/*查询姓名和邮箱不为空且年龄不小于12的结果*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}

@Test
void wrapperTest2() {
/*查询姓名为Tom的结果*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.eq("name","Tom");
/*查询的数据只有一个使用selectOne*/
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}

@Test
void wrapperTest3() {
/*查询年龄在[12,21]的结果*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",12,21);
Integer count = userMapper.selectCount(wrapper);
System.out.println(count);
}

@Test
void wrapperTest4() {
/*查询name NOT LIKE '%T%'
email LIKE '5%'
的结果*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.notLike("name","T")
.likeRight("email","5");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}

@Test
void wrapperTest5() {
/*子查询*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from user where id<4");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}

@Test
void wrapperTest6() {
/*根据id降序排列*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
}

代码自动生成器

Mybatis-plus-generator

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

Mybatis-Plus 3.5.1 以下

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!--自动生成代码ApiModel报错-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
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
public class MyAutoGenerator {
public static void main(String[] args) {
/*代码生成器*/
AutoGenerator mpg = new AutoGenerator();

/*全局配置*/
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("ZERO");
gc.setOpen(false);
gc.setFileOverride(false); /*是否覆盖*/
gc.setServiceName("%sService"); /*去掉Service的I前缀*/
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true); /*实体属性 Swagger2 注解*/
mpg.setGlobalConfig(gc);

/*数据源配置*/
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimeZone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("1234");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);

/*包配置*/
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog");
pc.setParent("com.zero");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);

/*模板引擎velocity*/
/* String templatePath = "/templates/mapper.xml.vm";*/



/* 策略配置 */
StrategyConfig strategy = new StrategyConfig();
/*映射表名*/
strategy.setInclude("user");
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
/*Lombok*/
strategy.setEntityLombokModel(true);
/*逻辑删除字段*/
strategy.setLogicDeleteFieldName("deleted");

/*自动填充设置*/
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
/*乐观锁字段配置*/
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute();
}
}