MyBatisPlus

小德 2021-12-02 12:57:59
Categories: Tags:

MyBatisPlus

0 lombok 插件问题

我们可以使用 Lombok 的 @Data标签,不用手动添加get set方法,但是如果项目中其他类中使用get、set方法,如果报错,原因是idea中没有添加Lombok插件,添加上插件便可以解决

在 IDEA的 setting 中,找到 Plugins. 搜索 lombok 。

1 mybatisPlus位置

1
官网地址:https://baomidou.com/

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

特性: 优点: 看官网介绍。

image-20210421100451905

然后可以在Bean上使用:

@Data :自动提供getter和setter、hashCode、equals、toString等方法

@Getter:自动提供getter方法

@Setter:自动提供setter方法

@Slf4j:自动在bean中提供log变量,其实用的是slf4j的日志功能。
@NoArgsConstructor,

@AllArgsConstructor,

https://www.cnblogs.com/ooo0/p/12448096.html

2 mybatisplus的第一个案例

数据表结构参照官网 快速开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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)
);
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');

创建springboot工程。

主要POM文件是:

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
<?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>2.3.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lpc</groupId>
<artifactId>mp4</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>mp4</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

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

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

​ 创建实体类

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

数据源配置信息

1
2
3
4
5
6
7
8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/myjpa?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#spring.datasource.initialization-mode=always

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

创建Mapper映射文件 接口

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

在启动类扫描

1
2
3
4
5
6
7
@SpringBootApplication
@MapperScan("com.lpc.mapper")
public class Mp4Application {
public static void main(String[] args) {
SpringApplication.run(Mp4Application.class, args);
}
}

​ 在测试类 测试即可。

测试情况 抄 官网

3 配置日志 显示执行的Sql

配置日志 默认的控制台输出

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

4 CRUD 测试

4.1 插入测试

1
2
3
4
5
6
7
8
9
@Test
void inserttest(){
User user=new User();
user.setAge(100);
user.setEmail("123@qq.com");
user.setName("张三");
userMapper.insert(user);
System.out.println(user);
}

插入之后会发现 自动 插入了ID值

Parameters: 1384691084839411714(Long), 张三(String), 100(Integer), 123@qq.com(String)

在核心功能的自定义 ID 生成器。 在文档中 中可以查看 自定义ID生成器

此ID 默认 用了 雪花算法来实现。可以参照:

https://www.cnblogs.com/haoxinyue/p/5208136.html

1
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0

实体类

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type=IdType.INPUT)
private Long id;
private String name;
private Integer age;
private String email;
}

可以配置成自己输入的。

4.2 删除测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
单个删除

userMapper.deleteById(6666);


批量删除:
List<Long> list=new ArrayList<>();
list.add(1415693168090914817L);
list.add(1415693532735270913L);
userMapper.deleteBatchIds(list);

DELETE FROM user WHERE id IN ( ? , ? )


Map删除 底层 用 and 拼接:

Map<String,Object> map=new HashMap<>();
map.put("name","Jone");
map.put("age",18);
userMapper.deleteByMap(map);



4.3 修改测试

修改 在 文档的 CRUD接口中的 Update这里。。

1
2
3
4
5
6
7
8
9
10
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereEntity 条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
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
根据id单个修改

@Test
void updatetest(){
User user=new User();
user.setAge(100);
user.setEmail("123@qq.com");
user.setName("李四");
userMapper.updateById(user);
}

也可以根据传入条件 查询:
@Test
public void xg() {
User user=new User();
user.setAge(100);
user.setEmail("1232323@qq.com");
user.setName("张分双方的士大夫三");
UpdateWrapper wrapper=new UpdateWrapper();
wrapper.eq("id",1415587633979031553L);
userMapper.update(user,wrapper);
}

条件具体构造:
https://blog.csdn.net/typ1805/article/details/84649606

修改的时候 自动拼接Sql

自动填充时间 如数据的插入时间,修改时间等。

自动填充有数据库级别的自动填充 和 程序级别的自动填充

4.4 数据库级别自动填充

设置 默认时间为 CURRENT_TIMESTAMP

修改时间 勾选 根据当前时间戳更新。

image-20210422100430179

​ 添加字段

1
2
private Date inserttime;
private Date updatetime;

重新测试插入数据 和修改数据 。即可测试到效果。

4.5 代码级别自动填充

​ 用mybatisplus 来 做自动填充,删除上面 所做的默认时间戳。

1
2
3
4
5
6
// 插入的时候更新
@TableField(fill=FieldFill.INSERT)
private Date inserttime;
// 插入和更新的时候都更新
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date updatetime;

然后写处理器 处理 注解。 官网上看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
public class MyBatisPlusTime implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.fillStrategy(metaObject, "inserttime", new Date());
this.fillStrategy(metaObject, "updatetime", new Date());
}

@Override
public void updateFill(MetaObject metaObject) {
this.fillStrategy(metaObject, "updatetime", new Date());
}
}

自动填充问题:
https://blog.csdn.net/kingwinstar/article/details/113418552
image-20210422103228930

​ 删除操作:

1
2
3
4
5
// 测试真实删除
@Test
void deleteuser(){
userMapper.deleteById(1);
}
// 查询
@Test
void selectAlltest(){
    List<User> list= userMapper.selectBatchIds(Arrays.asList(1,2,3));
    list.forEach(System.out::println);
}

4.6 测试逻辑删除

逻辑删除的理念是 标记一个状态 让查询通过这个状态, 不真实的 从数据库删除。 看文档。

可以给表中做一个 deleted 字段。

如 deleted = 0 是 正常状态 deleted =1 是删除状态。

操作: 1 在数据库中 添加 deleted 字段 默认是 0

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
1 在数据库中 添加 deleted   字段  默认是  0

2 在实体类中配置:

@TableLogic
private int deleted;


3 在application.properties 中配置

mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-delete-field=deleted



4 测试:
// 测试逻辑删除
@Test
void deleteuser1(){
userMapper.deleteById(2);
}

看生成的Sql语句,可以 再查询

User user= userMapper.selectById(2);
System.out.println(user);

可观察生成的 Sql.
SELECT id,name,age,email,deleted FROM user WHERE id=? AND deleted=0

4.7 条件查询构造器 Wrapper

1
2
3
4
5
6
7
8
@Test
void wappertest(){
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.like("name","李");
queryWrapper.eq("age",100);
List<User> list=userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}

4.8 查询测试

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
1  selectById

User user= userMapper.selectById(2);
System.out.println(user);

2 selectCount

int a= userMapper.selectCount(null);

3 selectBatchIds

List<Integer> list=new ArrayList<>();
list.add(2);
list.add(3);
list.add(4);
List<User> users= userMapper.selectBatchIds(list);
users.forEach(System.out::println);

4 selectByMap
Map<String,Object> map=new HashMap<>();
map.put("name","Jack");
map.put("age",20);
List<User> users= userMapper.selectByMap(map);
users.forEach(System.out::println);

5 selectList(wrapper);

QueryWrapper wrapper=new QueryWrapper();
wrapper.like("name","T");
wrapper.gt("age",20);
List<User> userList =userMapper.selectList(wrapper);
userList.forEach(System.out::println);

5 乐观锁

​ 当要更新一条记录的时候,希望这条记录没有被别人更新 看文档
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

操作:

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
1 给 表中 和字段中 加 version, 默认是 1

2 在 表字段的 version 上面加 @Version 表示是个乐观锁。

@Version
private Integer version;

3 在 spring boot注解方式: 看官网

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


@EnableTransactionManagement
@Configuration
public class MyConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}

image-20210422110506927
1
2
3
4
5
6
7
8
9
 // 测试更新  测试更新的时候一定要 先查询
@Test
void updatetest(){
User user=userMapper.selectById(1385046598274363393L);
user.setAge(104330);
user.setEmail("1332431@qq.com");
user.setName("4311李四12323");
userMapper.updateById(user);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 测试乐观锁 更新  多线程情况下
@Test
void updatetest1(){

User user=userMapper.selectById(1385046598274363393L);
user.setAge(100);
user.setEmail("1231@qq.com");
user.setName("999你好我好12323");
User user1=userMapper.selectById(1385046598274363393L);
user1.setAge(100);
user1.setEmail("1231@qq.com");
user1.setName("77你好我好12323");

userMapper.updateById(user1);
userMapper.updateById(user);
}

后面的 不会成功。

6 分页

PaginationInnerInterceptor

导入分页插件,分页插件和乐观锁插件是重合的。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@MapperScan("com.lpc.mapper")
@EnableTransactionManagement //事务处理
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 添加 Mybatis的分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}

测试分页:

1
2
3
4
5
6
7
// 测试分页插件
@Test
void selectpage(){
Page page = new Page(1,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}

Page中参数详解:

1
2
3
4
5
6
7
8
9
10
11
参数名	       参数类型    	默认值	    描述
records List<T> 用来存放查询出来的数据
total long 返回记录的总数
size long 每页显示条数
current long 当前页
orders List<OrderItem> 排序字段信息
optimizeCountSql boolean true 自动优化 COUNT SQL
isSearchCount boolean true 是否进行 count 查询,设置false后不会返回total
hitCount boolean false 是否命中count缓存
countId String 暂时未知
maxLimit Long null 单页分页条数限制

7 代码生成器

1
2
3
4
5
6
7
8
9
10
11
12
核心功能:
代码生成器:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</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
public class CodeGenerator {
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("lpc");
gc.setOpen(false); // 是否打开资源管理器
gc.setFileOverride(false); // 是否覆盖原来生成的代码
gc.setIdType(IdType.ASSIGN_UUID); // 设置主键生成策略
//gc.setSwagger2(true); // 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc); // 全局配置设置到代码生成器

// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/myjpa?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);

// 包配置
PackageConfig pc = new PackageConfig();
// pc.setModuleName(""); // 设置模块的名字
pc.setParent("com.xmx"); // 父包
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");

mpg.setPackageInfo(pc);


// 策略配置
StrategyConfig strategy = new StrategyConfig();

strategy.setInclude("student","teacher"); // 生成哪个表 设置哪个表 可变参数,可以设置多个
strategy.setNaming(NamingStrategy.underline_to_camel); // 下划线转驼峰
strategy.setColumnNaming(NamingStrategy.underline_to_camel);

strategy.setEntityLombokModel(true); // 链式编程
strategy.setRestControllerStyle(true);
// strategy.setLogicDeleteFieldName("deleted"); // 逻辑删除的字段 有就配置
// strategy.setVersionFieldName(""); // 乐观锁名字
// 写于父类中的公共字段
//strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true); // 请求映射转化 下划线 localhost:8080/hello_id_100
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);

mpg.execute(); // 执行

System.out.println(111111111);
}
}