一、官方介绍
支持的数据库
- mysql,oracle,db2,h2,hsql,sqlite,postgresql,sqlserver,Phoenix,Gauss ,clickhouse,Sybase,OceanBase,Firebird,cubrid,goldilocks,csiidb,informix,TDengine,redshift
- 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库
属性介绍
属性名 | 类型 | 默认值 | 描述 |
overflow | boolean | false | 溢出总页数后是否进行处理(默认不处理,参见 插件#continuePage 方法) |
maxLimit | Long | 单页分页条数限制(默认无限制,参见 插件#handlerLimit 方法) | |
dbType | DbType | 数据库类型(根据类型获取应使用的分页方言,参见 插件#findIDialect 方法) | |
dialect | IDialect | 方言实现类(参见 插件#findIDialect 方法) |
建议单一数据库类型的均设置 dbType
自定义的 mapper#method 使用分页
IPage selectPageVo(IPage> page, Integer state);
// or (class MyPage extends Ipage{ private Integer state; })
MyPage selectPageVo(MyPage page);
// or
List selectPageVo(IPage page, Integer state);
如果返回类型是 IPage 则入参的 IPage 不能为null,因为 返回的IPage == 入参的IPage; 如果想临时不分页,可以在初始化IPage时size参数传 <0 的值;
如果返回类型是 List 则入参的 IPage 可以为 null(为 null 则不分页),但需要你手动 入参的IPage.setRecords(返回的 List);
如果 xml 需要从 page 里取值,需要 page.属性 获取
其他:
生成 countSql 会在 left join 的表不参与 where 条件的情况下,把 left join 优化掉
所以建议任何带有 left join 的sql,都写标准sql,即给于表一个别名,字段也要 别名.字段
注意!
- 多个插件使用的情况,请将分页插件放到 插件执行链 最后面。如在租户插件前面,会出现 COUNT 执行 SQL 不准确问题。
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 |
二、简单使用
配置分页插件
@Configuration
public class MybatisConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
在高版本的SpringBoot中, 会提示这种写法已过时, 所以采用另一种写法 MybatisPlusInterceptor , 如下:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
MybatisPlusInterceptor
目前MybatisPlusInterceptor作为核心插件,代理了 Executor#query 和 Executor#update 和 StatementHandler#prepare 方法
属性
private List interceptors = new ArrayList<>();
InnerInterceptor
我们提供的插件都将基于此接口来实现功能 目前已有的功能: 自动分页:
PaginationInnerInterceptor 多租户:
TenantLineInnerInterceptor 动态表名:
DynamicTableNameInnerInterceptor 乐观锁:
OptimisticLockerInnerInterceptor sql性能规范:
IllegalSQLInnerInterceptor 防止全表更新与删除:
BlockAttackInnerInterceptor 注意: 使用多个功能需要注意顺序关系,建议使用如下顺序 多租户 动态表名 分页,乐观锁 sql性能规范,防止全表更新与删除 总结: 对sql进行单次改造的优先放入,不对sql进行改造的最后放入
编写Mapper及其对应的mapper.xml文件
@Mapper
public interface UserMapper extends BaseMapper {
List findPageUsers(Page page);
}
编写测试类
简单的分页查询
@SpringBootTest
class MybatisPlusStudyApplicationTests {
@Resource
UserMapper userMapper;
@Test
void contextLoads() {
Page page = new Page<>(1, 3);
List pageUsers = userMapper.findPageUsers(page);
page.setRecords(pageUsers);
System.out.println(page);
}
}
运行结果:
JsqlParserCountOptimize sql=select * from `user`
==> Preparing: SELECT COUNT(1) FROM `user`
==> Parameters:
<== Columns: COUNT(1)
<== Row: 9
==> Preparing: select * from `user` LIMIT ?
==> Parameters: 3(Long)
<== Columns: id, name, age
<== Row: 41ee81ff-fc0c-8bfa-77d8-44c190cc7466, aaa, 12
<== Row: 3b25fb904548c28b7ac6882d86c7ae5f, bbb, 12
<== Row: 8b0397fcdfebe37d1d26175c17ed3725, ccc, 12
<== Total: 3
带查询条件的分页查询
此方法是使用PaginationInterceptor 作为分页插件.
@Test
void contextLoads() {
Page page = new Page<>(1, 2);
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "bbb");
Page page1 = userMapper.selectPage(page, queryWrapper);
page.setRecords(page1.getRecords()).getRecords().forEach(System.out::println);
}
运行结果:
JsqlParserCountOptimize sql=SELECT id,name,age FROM user
WHERE (name = ?)
==> Preparing: SELECT COUNT(1) FROM user WHERE (name = ?)
==> Parameters: wdh(String)
<== Columns: COUNT(1)
<== Row: 5
==> Preparing: SELECT id,name,age FROM user WHERE (name = ?) LIMIT ?
==> Parameters: wdh(String), 2(Long)
<== Columns: id, name, age
<== Row: b78cbc0d-82f8-2f57-90c5-5f0a308ee4a5, bbb, 12
<== Row: 4febef0e-409d-a540-7b42-b3815c5a1956, ccc, 12
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6a0f2853]
User(id=3b25fb904548c28b7ac6882d86c7ae5f, name=bbb, age=12)
User(id=8b0397fcdfebe37d1d26175c17ed3725, name=ccc, age=12)
Page
简单分页模型, 有如下几个主要属性
/**
* 查询数据列表
*/
protected List records = Collections.emptyList();
/**
* 总数
*/
protected long total = 0;
/**
* 每页显示条数,默认 10
*/
protected long size = 10;
/**
* 当前页
*/
protected long current = 1;
注意事项
在编写mapper.xml中的SQL语句的时候, 语句末尾不能使用 ; 结尾, 原因是在做分页的时候会在编写的SQL语句后面拼接上limit语句, 导致出现SQL语法错误(SQLSyntaxErrorException). 如下所示:
JsqlParserCountOptimize sql=select *
from `user`;
==> Preparing: SELECT COUNT(1) FROM `user`
==> Parameters:
<== Columns: COUNT(1)
<== Row: 9
==> Preparing: select * from `user`; LIMIT ?
==> Parameters: 3(Long)
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 3' at line 1
### The error may exist in org/wxmx/mybatis_plus_study/mapper/UserMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select * from `user`; LIMIT ?
### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 3' at line 1
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax;