天天看點

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;