MyBatis Plus
文章目录
- MyBatis Plus
- 1. 简介
- 2. 入门使用
- 3. 核心功能
- 3.1 CRUD 接口
- 3.1.1 Mapper CRUD 接口
- 3.1.2 Service CRUD 接口
- 3.2 条件构造器
- 3.3 分页插件
- 3.4 Mybatis-Plus 注解
- 4. 拓展
- 4.1 逻辑删除
- 4.2 MybatisX快速开发插件
- 5. 插件
- 5.1 [分页插件](#page)
- 5.2 乐观锁插件
1. 简介
MyBatis Plus,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。官网:https://baomidou.com/ ,下面功能及使用都可从官网找到
MyBatis Plus 具有以下特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
2. 入门使用
-
创建Maven工程
-
添加依赖,这里给一份 springboot3 较为完整依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-3-starter</artifactId> <version>1.2.20</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
-
启动类配置
@MapperScan("com.springboot.mapper")
mapper接口扫描注解 -
配置文件
application.yaml
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: username: root password: root url: jdbc:mysql:///mybatisplus driver-class-name: com.mysql.cj.jdbc.Driver
-
编写 mapper 接口,继承
BaseMapper
,继承mybatis-plus提供的基础Mapper接口,将自带crud方法
部分约定配置:
map-underscore-to-camel-case
:下划线驼峰命名,默认开启
mapper扫描:classpath*:/mapper/**/*.xml
3. 核心功能
3.1 CRUD 接口
3.1.1 Mapper CRUD 接口
官网:https://baomidou.com/pages/49cc81/#mapper-crud-接口
使用时:ScheduleMapper extends BaseMapper<Schedule>
- 通用 CRUD 封装
BaseMapper
接口,为Mybatis-Plus
启动时自动解析实体表关系映射转换为Mybatis
内部对象注入容器 - 泛型
T
为任意实体对象 - 参数
Serializable
为任意类型主键Mybatis-Plus
不推荐使用复合主键约定每一张表都有自己的唯一id
主键 - 对象
Wrapper
为 条件构造器
ScheduleMapper
将包含 BaseMapper
中的一系列增删改查及分页查询方法
3.1.2 Service CRUD 接口
官网:https://baomidou.com/pages/49cc81/#service-crud-接口
- 通用 Service CRUD 封装 IService 接口,进一步封装 CRUD 采用
get 查询单行
remove 删除
list 查询集合
page 分页
前缀命名方式区分Mapper
层避免混淆 - 泛型
T
为任意实体对象 - 建议如果存在自定义通用 Service 方法的可能,请创建自己的
IBaseService
继承Mybatis-Plus
提供的基类 - 对象
Wrapper
为 条件构造器
3.2 条件构造器
Wrapper : 条件构造抽象类,最顶端父类
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- QueryWrapper : 查询/删除条件封装
- UpdateWrapper : 修改条件封装
- AbstractLambdaWrapper : 使用Lambda 语法
- LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper : Lambda 更新封装Wrapper
组装条件:
这里仅介绍基于 Lambda 的条件封装的使用,非 Lambda 自行创建对象 QueryWrapper 用类似方法进行拼接即可
LambdaQueryWrapper
@RequestMapping("query")
public Result<List<Schedule>> query() {
LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Schedule::getId, 2);
return new Result<>(scheduleService.list(queryWrapper));
}
LambdaUpdateWrapper :使用 set()
方法设置属性
@RequestMapping("update")
public Result<Boolean> update() {
LambdaUpdateWrapper<Schedule> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Schedule::getId, 2).eq(Schedule::getCompleted, 0);
updateWrapper.set(Schedule::getCompleted, 1).set(Schedule::getTitle, "学个P呀");
return new Result<>(scheduleService.update(updateWrapper));
}
3.3 分页插件
配置方法:配置类中,将 MybatisPlusInterceptor
注入 IoC容器中,注入前添加 PaginationInnerInterceptor
拦截器
@MapperScan("com.springboot.mapper")
@SpringBootApplication
public class SpringBootApplicationMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplicationMain.class);
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
使用默认实现的分页:scheduleService.page
返回的是 Page
对象,与 new Page
是同一个,只是对象中有了更多信息
@RequestMapping("query")
public Result<Page<Schedule>> query() {
Page<Schedule> page = new Page<>(1,5);
return new Result<>(scheduleService.page(page));
}
Page :该类继承了 IPage
类,实现了 简单分页模型
如果你要实现自己的分页模型可以继承 Page
类或者实现 IPage
类
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
records | List | emptyList | 查询数据列表 |
total | Long | 0 | 查询列表总记录数 |
size | Long | 10 | 每页显示条数,默认 10 |
current | Long | 1 | 当前页 |
orders | List | emptyList | 排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本 |
optimizeCountSql | boolean | true | 自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false |
optimizeJoinOfCountSql | boolean | true | 自动优化 COUNT SQL 是否把 join 查询部分移除 |
searchCount | boolean | true | 是否进行 count 查询,如果只想查询到列表不要查询总记录数,设置该参数为 false |
maxLimit | Long | 单页分页条数限制 | |
countId | String | xml 自定义 count 查询的 statementId 也可以不用指定在分页 statementId 后面加上 _mpCount 例如分页 selectPageById 指定 count 的查询 statementId 设置为 selectPageById_mpCount 即可默认找到该 SQL 执行 |
自定义分页方法接口:
//传入参数携带Ipage接口
//返回结果为IPage
IPage<User> selectPageVo(IPage<?> page, Integer id);
<select id="selectPageVo" resultType="xxx.xxx.xxx.User">
SELECT * FROM user WHERE id > #{id}
</select>
如果返回类型是 IPage 则入参的 IPage 不能为null,因为 返回的 IPage == 入参的IPage;如果想临时不分页,可以在初始化 IPage 时 size 参数传 <0 的值;
如果返回类型是 List 则入参的 IPage 可以为 null(为 null 则不分页),但需要你手动 入参的IPage.setRecords(返回的 List);
如果 xml 需要从 page 里取值,需要page.属性
获取
注意:多个插件使用的情况,请将分页插件放到 插件执行链
最后面。如在租户插件前面,会出现 COUNT
执行 SQL
不准确问题
3.4 Mybatis-Plus 注解
详情可参考官网:https://baomidou.com/pages/223848/#tablename
@TableName
:表名注解,标识实体类对应的表@TableId
:主键注解。type指定为ASSIGN_ID
会调用主键生成默认实现类,以雪花算法生成 ID@TableField
:字段注解(非主键)@Version
:乐观锁注解@TableLogic
:逻辑处理注解,增加注解后删除会进行逻辑删除。默认逻辑删除属性已删除值为 1,未删除值为 0。也可通过mybatis-plus.global-config.db-config.logic-delete-field
配置全局逻辑删除属性。二者必须配置一个逻辑删除才会生效,注意也会影响默认查询逻辑,查询中会过滤逻辑删除的数据@OrderBy
:内置 SQL 默认指定排序,优先级低于 wrapper 条件查询
4. 拓展
4.1 逻辑删除
- 配置
application.yaml
,从 3.3.0 版本开始,可以忽略不配置@TableLogic
注解
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 实体类字段上加上
@TableLogic
注解
4.2 MybatisX快速开发插件
在 idea 插件中搜索 MybatisX
,安装后右侧导航栏(Datasbase
)连接数据源后,即可选择表右键直接生成代码
如果需要生成是子模块代码,这里需要手动填一下子模块目录,目前版本选中子模块不会自动填入,如我这里是 T01
relative package
:实体类的生成包
之后需选中 Model
才会生成实体类
5. 插件
目前已有的功能:
- 自动分页: PaginationInnerInterceptor
- 乐观锁: OptimisticLockerInnerInterceptor
- 多租户: TenantLineInnerInterceptor
- 动态表名: DynamicTableNameInnerInterceptor
- 非法SQL拦截: IllegalSQLInnerInterceptor
- 防止全表更新与删除: BlockAttackInnerInterceptor
- 数据权限:DataPermissionInterceptor
- 数据变动记录:DataChangeRecorderInnerInterceptor
插件配置:注入 MybatisPlusInterceptor
对象即可,注入前把需要的对应拦截器添加到该对象中
@MapperScan("com.springboot.mapper")
@SpringBootApplication
public class SpringBootApplicationMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplicationMain.class);
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
注意:
使用多个功能需要注意顺序关系,建议使用如下顺序
- 多租户,动态表名
- 分页,乐观锁
- sql 性能规范,防止全表更新与删除
总结: 对 sql 进行单次改造的优先放入,不对 sql 进行改造的最后放入
具体可参考官网使用:https://baomidou.com/pages/2976a3/
5.1 分页插件
5.2 乐观锁插件
配置完拦截器后在实体类的字段上加上 @Version
注解即可
说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
,newVersion
会回写到entity
中 - 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!