MyBatis-Plus
简介
MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
基于SpringBoot使用MyBatisPlus
数据库设计

新建项目




导入依赖

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
| <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
|
编辑配置

1 2 3 4 5 6 7
| spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC username: root password: 13851176590++
|
添加启动类

1 2 3 4 5 6
| @SpringBootApplication public class MyBatisPlusApplication { public static void main(String[] args) { SpringApplication.run(MyBatisPlusApplication.class, args); } }
|
创建实体类

1 2 3 4 5 6 7 8
| @Data public class User { private Long id; private String name; private String password; private Integer age; private String tel; }
|
创建Dao接口

1 2 3 4
| @Mapper public interface UserMapper extends BaseMapper<User> {
}
|
创建测试类

1 2 3 4 5 6 7 8 9 10 11 12
| @SpringBootTest public class MyBatisPlusApplicationTest { @Resource private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(MyBatisPlusApplicationTest.class); @Test void getAll(){ List<User> users = userMapper.selectList(null); logger.info("用户列表:" + users); } }
|
简化日志输出
新建logback.xml配置文件

编辑配置

1 2 3
| <?xml version="1.0" encoding="UTF-8"?> <configuration> </configuration>
|
关闭Banner

启动测试

标准数据层开发

新增操作

1 2 3 4 5
| @Test void saveUser() { User user = new User().setName("xiaohong").setAge(21).setPassword("123456").setTel("123456"); Integer count = userMapper.insert(user); }
|

删除操作


修改操作

1 2 3 4 5
| @Test void updateUser() { User user = new User().setId(1L).setAge(50); userMapper.updateById(user); }
|

分页查询
配置分页拦截器

编辑测试类


添加日志输出


DQL
条件查询
查看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
| @Test void getByQueryWrapper() { QueryWrapper<User> queryWrapper = new QueryWrapper<User>(); queryWrapper.gt("age", 20).lt("age", 40); List<User> users = userMapper.selectList(queryWrapper); users.forEach(user -> logger.info("用户:" + user)); } @Test void getByQueryWrapperForLambda() { QueryWrapper<User> queryWrapper = new QueryWrapper<User>(); queryWrapper.lambda().gt(User::getAge, 20).lt(User::getAge, 40); List<User> users = userMapper.selectList(queryWrapper); users.forEach(user -> logger.info("用户:" + user)); } @Test void getByLambdaQueryWrapper() { LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); lambdaQueryWrapper.gt(User::getAge, 20).lt(User::getAge, 40);
List<User> users = userMapper.selectList(lambdaQueryWrapper); users.forEach(user -> logger.info("用户:" + user)); }
|

空值判定
新建用户查询条件类

空值测试


空值判定方法
方法一:if条件语句控制

1 2 3 4 5 6 7 8 9 10 11 12 13 14
|  @Test void getByIfNull() { UserQuery userQuery = new UserQuery(); userQuery.setLowerAge(20).setUpperAge(40); LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); if (userQuery.getLowerAge() != null) { lambdaQueryWrapper.gt(User::getAge, userQuery.getLowerAge()); } if (userQuery.getUpperAge() != null) { lambdaQueryWrapper.lt(User::getAge, userQuery.getUpperAge()); } List<User> users = userMapper.selectList(lambdaQueryWrapper); users.forEach(user -> logger.info("用户:" + user)); }
|
方法二:条件参数控制

1 2 3 4 5 6 7 8 9 10
| @Test void getByCondition() { UserQuery userQuery = new UserQuery(); userQuery.setLowerAge(20).setUpperAge(40); LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); lambdaQueryWrapper.gt(userQuery.getLowerAge() !=null, User::getAge, userQuery.getLowerAge()) .lt(userQuery.getUpperAge() != null, User::getAge, userQuery.getUpperAge()); List<User> users = userMapper.selectList(lambdaQueryWrapper); users.forEach(user -> logger.info("用户:" + user)); }
|
查询投影
情况一:LambdaQueryWrapper

情况二:QueryWrapper

测试


1 2 3 4 5 6 7 8 9 10 11
| @Test void getTotal(){ QueryWrapper<User> queryWrapper = new QueryWrapper<User>(); queryWrapper.select("count(*) as total", "age"); queryWrapper.groupBy("age"); List<Map<String, Object>> map = userMapper.selectMaps(queryWrapper); System.out.println(map); }
|

查询条件设置
API查询地址:https://baomidou.com/pages/10c804/#nested
等值查询

1 2 3 4 5 6 7 8 9
| @Test void login() { LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); lambdaQueryWrapper.eq(User::getName, "xiaomi").eq(User::getPassword, "123456"); User user = userMapper.selectOne(lambdaQueryWrapper); System.out.println(user); }
|

范围查询

1 2 3 4 5 6 7 8 9 10
| @Test void between() { LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); lambdaQueryWrapper.between(User::getAge, 20, 40); List<User> users = userMapper.selectList(lambdaQueryWrapper); users.forEach(user -> { System.out.println(user); }); }
|

模糊匹配

1 2 3 4 5 6 7 8
| // 模糊匹配 @Test void like() { LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>(); lambdaQueryWrapper.like(User::getName, "xiao"); List<User> users = userMapper.selectList(lambdaQueryWrapper); users.forEach(System.out::println); }
|

映射匹配
数据库

实体类映射

测试

DML
Insert
id生成策略控制
场景分析


@TableId()注释

测试

全局配置

1 2 3 4 5 6 7 8
| mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: banner: false db-config: id-type: assign_id table-prefix: ums_
|

Delete
批量删除

1 2 3 4 5 6 7
| @Test void batchDelete() { List<Long> ids = Arrays.asList(new Long[]{1544234982638149633L, 1544235553495506945L}); Integer count = userMapper.deleteBatchIds(ids); }
|

逻辑删除
数据库添加逻辑删除字段

实体类添加字段并设定逻辑删除标记字段

测试

1 2 3 4 5
| @Test void deleteByLogic() { Integer count = userMapper.deleteById(1L); }
|




全局配置

Update
乐观锁
当更新一条记录时,希望这条记录没有被别人更新
乐观锁的实现方式:
- 取出记录时,获取当前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
| @Data @AllArgsConstructor @NoArgsConstructor @Builder @Accessors(chain = true) @EqualsAndHashCode(callSuper = false)
public class User {
private Long id; private String name; @TableField(value = "pwd", select = false) private String password; private Integer age; private String tel; @TableField(exist = false) private Integer online; @TableField(value = "is_delete") @TableLogic(value = "0", delval = "1") private Integer deleted; @Version private Integer version; }
|
添加配置

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }
|
测试

1 2 3 4 5 6 7
| @Test void update() { User user = new User().setId(3L).setName("aa") .setVersion(1); Integer count = userMapper.updateById(user); }
|

并发测试

1 2 3 4 5 6 7 8 9 10
| @Test void updateByConcurrency() { User user1 = userMapper.selectById(3L); User user2 = userMapper.selectById(3L); user1.setName("aa"); Integer count1 = userMapper.updateById(user1); user2.setName("bb"); Integer count2 = userMapper.updateById(user2); }
|


代码生成器
导入依赖

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
| <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <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.3</version> </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 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
public class Generator { public static void main(String[] args) { AutoGenerator autoGenerator = new AutoGenerator(); DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC"); dataSourceConfig.setUsername("root"); dataSourceConfig.setPassword("13851176590++"); autoGenerator.setDataSource(dataSourceConfig); GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir("D:\\Users\\YuanJW\\Desktop\\Java Learn\\MyBatis-Plus\\MyBatisPlusGenerator\\src\\main\\java") .setOpen(false) .setAuthor("xiaoyuanjw") .setFileOverride(true) .setMapperName("%sMapper") .setIdType(IdType.ASSIGN_ID); autoGenerator.setGlobalConfig(globalConfig); PackageConfig packageConfig = new PackageConfig(); packageConfig.setParent("com.example.demo") .setEntity("domain") .setMapper("dao"); autoGenerator.setPackageInfo(packageConfig); StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setInclude("ums_user") .setTablePrefix("ums_") .setRestControllerStyle(true) .setVersionFieldName("version") .setLogicDeleteFieldName("deleted") .setEntityLombokModel(true); autoGenerator.setStrategy(strategyConfig); autoGenerator.execute(); } }
|
生成结构
