# Mybatis-Plus
# 快速入门
maven依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
注意点:尽量不要同时导入mybatis和mybatis-plus依赖
# 配置:
# DataSource Config
spring:
datasource:
username: root
password: Theyear123
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&aharacterEncoding=utf-8&serverTimezone=UTC
1
2
3
4
5
6
7
2
3
4
5
6
7
User.java
package com.yixihan.mybatis_plus01hello.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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
UserMapper.java
package com.yixihan.mybatis_plus01hello.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yixihan.mybatis_plus01hello.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
//在对应的 mapper 上面集成基本的类 BaseMapper
@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
//所有的CRUD都已经编写完成了
//不需要向以前那样的配置一大堆文件了
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Application.java
package com.yixihan.mybatis_plus01hello;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.yixihan.mybatis_plus01hello")
public class MybatisPlus01HelloApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlus01HelloApplication.class, args);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Tests.java
package com.yixihan.mybatis_plus01hello;
import com.yixihan.mybatis_plus01hello.mapper.UserMapper;
import com.yixihan.mybatis_plus01hello.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 MybatisPlus01HelloApplicationTests {
//继承了 BaseMapper ,所有的方法都来自父类, 我们也可以编写自己的扩展方法
@Autowired
private UserMapper mapper;
@Test
void contextLoads() {
//参数是一个 Wrapper 条件构造器 不用就写 null
List<User> userList = mapper.selectList(null);
userList.forEach(System.out::println);
}
}
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
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
# 日记配置
logging.level.com.yixihan.mybatis_plus01hello.mapper=debug
1
或者
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1
2
3
2
3
# CRUD扩展
# 插入
@Test
public void insert() {
User user = new User();
user.setName("曾思彤");
user.setAge(18);
user.setEmail("3113788997@qq.com");
mapper.insert(user);
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 主键自增
配置ID自增操作:
- 实例类上加注解
@TableId(type = IdType.AUTO)
- 数据库字段要为自增
其他原码
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* 该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
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
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
# 更新
@Test
public void updateUser() {
User user = new User();
user.setId(8L);
user.setEmail("2535774265@qq.com");
//参数是对象
mapper.updateById(user);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 自动填充
数据库不设置默认值 根据当前时间戳更新等设置
实体类上加注解
//字段添加 填充内容 @TableField(fill = FieldFill.INSERT) private Date creatTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
1
2
3
4
53.编写处理器来处理
package com.yixihan.mybatis_plus01hello.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import java.util.Date; @Slf4j //不要忘了这个注解 @Component public class MyMetaObjectHandler implements MetaObjectHandler { //插入时候的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill..."); //default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) this.setFieldValByName("creatTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); log.info("insert success"); } //更新时候的填充策略 @Override public void updateFill(MetaObject metaObject) { log.info("start update fill..."); //default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) this.setFieldValByName("updateTime", new Date(), metaObject); log.info("update success"); } }
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
# 乐观锁
乐观锁:总是认为不会出现问题,无论干什么都不会上锁,如果出现了问题,再次更新值测试
悲观锁:总是认为总会出现问题,无论干什么都会上锁,再去操作
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
乐观锁:1.先查询,获得版本号 version = 1
---A
update user set name = 'yixihan',version = version + 1
where id = 2 and version = 1
---B B 线程抢先完成 这个时候 version = 2, 会导致 A 线程修改失败
update user set name = 'yixihan',version = version + 1
where id = 2 and version = 1
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
测试
- 更新数据库表
数据库表新增 version
列
- 修改实体类
//乐观锁 version 注解
@Version
private Integer version;
1
2
3
2
3
- 注册组件
package com.yixihan.mybatis_plus01hello.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@MapperScan("com.yixihan.mybatis_plus01hello")
@EnableTransactionManagement
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
测试代码
//测试乐观锁 成功
@Test
public void test1() {
//查询用户信息
User user = mapper.selectById(1L);
//修改用户信息
user.setName("yixihan");
user.setEmail("3113788997@qq.com");
//执行更新操作
mapper.updateById(user);
}
//测试乐观锁 失败 多线程下
@Test
public void test2() {
/*线程1*/
//查询用户信息
User user1 = mapper.selectById(1L);
//修改用户信息
user1.setName("yixihan111");
user1.setEmail("3113788997@qq.com");
/*模拟另外一个线程执行了插队操作*/
User user2 = mapper.selectById(1L);
user2.setName("yixihan2222");
user2.setEmail("3113788997@qq.com");
mapper.updateById(user2);
//执行更新操作
//自旋锁来尝试多次提交
mapper.updateById(user1); //如果没有乐观锁,就会覆盖插队线程的值
}
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
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
# 查询
//测试查询
@Test
public void testQueryById() {
User user = mapper.selectById(1L);
System.out.println(user);
}
//测试批量查询
@Test
public void testQueryByBatchIds() {
List<User> user = mapper.selectBatchIds(Arrays.asList(1,2,3));
user.forEach(System.out::println);
}
//测试条件查询 使用 map 操作
@Test
public void testQueryByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("age", 18);
List<User> users = mapper.selectByMap(map);
users.forEach(System.out::println);
}
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
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
# 分页查询
使用sql原生分页查询 limit
SELECT * FROM `user` LIMIT 1,5
SELECT * FROM `user` WHERE age = 18 LIMIT 1,3
1
2
3
2
3
使用第三方插件:PageHelper
官网地址:https://pagehelper.github.io/
使用MP自带的分页插件
- 配置拦截器
// 配置分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
1
2
3
4
5
2
3
4
5
- 直接使用 page 对象即可
//测试分页查询
@Test
public void testPage() {
//参数一:当前页
//参数二:页面大小
Page<User> page = new Page<>(2,5);
mapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 删除操作
基本删除操作
//测试删除
@Test
public void testDeleteById() {
mapper.deleteById(1419446855594430467L);
}
//批量删除 通过ID
@Test
public void testBatchIds() {
mapper.deleteBatchIds(Arrays.asList(6,8));
}
//条件删除 通过map
@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("age", 18);
mapper.deleteByMap(map);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 逻辑删除
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有移除,而是通过变量让他失效 deleted=0=>deleted=1
逻辑删除乐意防止数据丢失,类似回收站
- 在数据库中新增列
增加 deleted
列
- 更改实体类
//逻辑删除
@TableLogic
private Integer deleted;
1
2
3
2
3
- 配置组件
//逻辑删除组件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
1
2
3
4
5
2
3
4
5
mybatis:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
1
2
3
4
5
6
2
3
4
5
6
# 性能分析插件
- 导入插件
//sql 执行效率插件
@Bean
@Profile({"test","dev"}) //设置 dev test 环境开启,保证效率
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor paginationInterceptor = new PerformanceInterceptor();
//ms 设置 sql 执行的最大时间,如果超过了则不执行
paginationInterceptor.setMaxTime(100);
//设置格式化
paginationInterceptor.setFormat(true);
return paginationInterceptor;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
配置环境
spring:
profiles:
active: dev
1
2
3
2
3
# 条件构造器 Wrapper
测试代码:
package com.yixihan.mybatis_plus01hello;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yixihan.mybatis_plus01hello.mapper.UserMapper;
import com.yixihan.mybatis_plus01hello.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;
import java.util.Map;
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper mapper;
@Test
public void contextLoads() {
//查询 name 且 email 不为空, age > 18 岁的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age", 18);
List<User> userList = mapper.selectList(wrapper);
userList.forEach(System.out::println);
}
@Test
public void contextLoads2() {
//查询 名字为 Billie 的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "Billie");
//查询一个数据 ,如果多个的话,用List/Map
User user = mapper.selectOne(wrapper);
System.out.println(user);
}
@Test
public void contextLoads3() {
//查询 年龄在 20-30 之间的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 20, 30);
//查询一个数据 ,如果多个的话,用List/Map
Integer count = mapper.selectCount(wrapper);
System.out.println(count);
}
//模糊查询
@Test
public void contextLoads4() {
//左和右, 代表 % 在哪边
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.notLike("name", "小")
.likeRight("email","t");
List<Map<String, Object>> maps = mapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
//内嵌查询
@Test
public void contextLoads5() {
//ID 在子查询中查询出来
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id", "select id from user where id < 4");
List<Object> objects = mapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
//查询排序
@Test
public void contextLoads6() {
//通过 ID 进行排序
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
List<User> userList = mapper.selectList(wrapper);
userList.forEach(System.out::println);
}
}
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 代码自动生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
package com.yixihan;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
// 代码自动生成器
public class autoCode {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("易曦翰");
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆盖
gc.setServiceName("%sService"); // 去Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、设置数据源
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("Theyear123");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("User");
pc.setParent("com.yixihan");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user"); // 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", 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); //localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}
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
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
需导入依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.swagger/swagger-annotations -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24