一、Mybatis分頁查詢介紹
Mybatis是一款優秀的持久層框架,支持動態SQL和參數映射等功能,而分頁查詢也是其中非常重要的功能之一。
分頁查詢是指將大量的數據按照需要的記錄數分為多個頁面展示,適用於大型數據查詢和數據展示。
二、Mybatis分頁查詢實現
Mybatis分頁查詢可以通過SQL語句的limit關鍵字實現,不同的數據庫語法略有不同,下面是兩種常見的方式:
mysql:SELECT * FROM table LIMIT 0, 10; oracle:SELECT * FROM (SELECT a.*, ROWNUM rn FROM table a WHERE ROWNUM = 0;
MySQL使用”limit start,pageSize”來實現分頁,其中start為起始行數,pageSize為每頁數量。而Oracle則需要使用子查詢和ROWNUM來實現相同的效果。
但是,這種方式並不是最優的分頁查詢方式,因為它會先查詢所有數據,然後再根據指定的起始行數和數量來返回結果集。同時又因為Mybatis是懶加載的,只有在調用結果集時才會產生真正的SQL查詢,所以需要改進這種實現方式。
三、Mybatis分頁插件介紹
Mybatis分頁插件可以屏蔽底層的分頁SQL,通過攔截StatementHandler接口的prepare方法,實現物理分頁,減少查詢不必要的數據傳輸和內存消耗,提高查詢效率。
下面是Mybatis分頁插件的示例代碼:
public class PageInterceptor implements Interceptor { private static final ThreadLocal LOCAL_PAGE = new ThreadLocal(); /** * 插件實現方法 */ @Override public Object intercept(Invocation invocation) throws Throwable { // 獲取當前真正執行的SQL語句 MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; String sqlId = mappedStatement.getId(); BoundSql boundSql = mappedStatement.getBoundSql(parameterObject); // 只攔截需要分頁的SQL語句 if (isPageSql(sqlId)) { Object parameterObject = boundSql.getParameterObject(); Page page = null; // 獲取分頁參數 if (parameterObject instanceof Page) { page = (Page) parameterObject; } else if (parameterObject instanceof Map) { for (Object arg : ((Map) parameterObject).values()) { if (arg instanceof Page) { page = (Page) arg; break; } } } if (page == null) { throw new IllegalArgumentException("Page parameter not found"); } // 修改SQL語句 String sql = boundSql.getSql(); String newSql = sql + " limit " + page.getStart() + "," + page.getPageSize(); ReflectUtil.setFieldValue(boundSql, "sql", newSql); LOCAL_PAGE.set(page); } // 執行原SQL Object result = invocation.proceed(); if (LOCAL_PAGE.get() != null) { // 封裝查詢結果 PageList pageList = new PageList((List) result, LOCAL_PAGE.get()); LOCAL_PAGE.remove(); return pageList; } return result; } /** * 是否是分頁SQL */ private boolean isPageSql(String sqlId) { return sqlId.matches(".+Page$") || sqlId.matches(".+PageX$") || sqlId.matches(".+PageX?[0-9]*$"); } // 省略其他代碼 }
這裡使用了ThreadLocal類來將分頁參數綁定到當前線程中,在分頁參數封裝後再進行返回。主要使用了ReflectUtil.setFieldValue()方法修改BoundSql中的SQL語句。
四、Mybatis分頁查詢使用方法
使用Mybatis分頁插件進行分頁查詢非常簡單,只需要按照以下步驟配置即可:
- 在mybatis-config.xml中添加插件:
- 在Mapper.xml中添加分頁SQL語句:
- 在Java代碼中調用分頁查詢方法:
- Mybatis分頁插件主要實現了Intercepter接口和Invocation接口,其中Intercepter接口用來對SQL語句進行攔截和修改,Invocation接口則用來執行真正的SQL語句和返回結果。
- Mybatis分頁插件使用了ThreadLocal類來將分頁參數綁定到當前線程中,避免了多線程並發訪問時的參數混淆問題。
- Mybatis分頁插件實現了自定義註解、Mapper接口和XML映射文件的自動綁定機制,可以大大減少開發工作量。
- 分頁參數必須是一個Java對象,並且至少包含起始行數和每頁數量兩個屬性。
- 分頁參數必須綁定到Mapper接口的方法參數中。
- 分頁查詢SQL語句必須以limit為結尾。
- 分頁插件使用了反射機制和強制類型轉換,請注意避免出現類型轉換異常。
<plugins> <plugin interceptor="com.example.PageInterceptor"></plugin> </plugins>
<select id="findUserPage" parameterType="map" resultType="com.example.User"> select * from user where 1=1 <if test="username != null"> and username like '%${username}%</if> <if test="age != null"> and age = #{age}</if> <if test="gender != null"> and gender = #{gender}</if> limit #{page.start},#{page.pageSize} </select>
Page page = new Page(1, 10); Map param = new HashMap(); param.put("username", "test"); param.put("age", 18); param.put("gender", 1); param.put("page", page); List userList = userDao.findUserPage(param);
其中,Page是分頁參數封裝類,包含起始行數和每頁數量兩個屬性。
五、Mybatis分頁插件源碼解析
Mybatis分頁插件源碼解析可以深入理解其實現原理和機制,這裡只簡要介紹:
六、Mybatis分頁查詢注意事項
使用Mybatis分頁插件進行分頁查詢需要注意以下事項:
七、總結
Mybatis分頁查詢是非常重要的功能,可以大大提高查詢效率和降低內存消耗。可以通過Mybatis分頁插件進行快速、簡便的實現,並根據需要進行一定的自定義修改。
原創文章,作者:QPOIO,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/371731.html