天天看点

SpringBoot集成Mybatis-Plus分页插件

作者:北风浊酒
SpringBoot集成Mybatis-Plus分页插件

一、官方介绍

支持的数据库

  • 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<UserVo> selectPageVo(IPage<?> page, Integer state);
// or (class MyPage extends Ipage<UserVo>{ private Integer state; })
MyPage selectPageVo(MyPage page);
// or
List<UserVo> selectPageVo(IPage<UserVo> page, Integer state);
           
<select id="selectPageVo" resultType="xxx.xxx.xxx.UserVo">
    SELECT id,name FROM user WHERE state=#{state}
</select>
           

如果返回类型是 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 查询列表总记录数
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<InnerInterceptor> interceptors = new ArrayList<>();           

InnerInterceptor

我们提供的插件都将基于此接口来实现功能 目前已有的功能: 自动分页: PaginationInnerInterceptor 多租户: TenantLineInnerInterceptor 动态表名: DynamicTableNameInnerInterceptor 乐观锁: OptimisticLockerInnerInterceptor sql性能规范: IllegalSQLInnerInterceptor 防止全表更新与删除: BlockAttackInnerInterceptor 注意: 使用多个功能需要注意顺序关系,建议使用如下顺序 多租户 动态表名 分页,乐观锁 sql性能规范,防止全表更新与删除 总结: 对sql进行单次改造的优先放入,不对sql进行改造的最后放入

编写Mapper及其对应的mapper.xml文件

@Mapper
public interface UserMapper extends BaseMapper<User> {
    List<User> findPageUsers(Page<User> page);
}           
<select id="findPageUsers" resultType="com.test.entity.User">
    select * from `user`
</select>           

编写测试类

简单的分页查询

@SpringBootTest
class MybatisPlusStudyApplicationTests {
    @Resource
    UserMapper userMapper;
    @Test
    void contextLoads() {
        Page<User> page = new Page<>(1, 3);
        List<User> 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<User> page = new Page<>(1, 2);
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("name", "bbb");
    Page<User> 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<T> 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;