幾種常見mybatis分頁的實(shí)現(xiàn)方式
幾種常見mybatis分頁實(shí)現(xiàn)
mybatis框架分頁實(shí)現(xiàn),有幾種方式,最簡(jiǎn)單的就是利用原生的sql關(guān)鍵字limit來實(shí)現(xiàn),還有一種就是利用interceptor來拼接sql,實(shí)現(xiàn)和limit一樣的功能,再一個(gè)就是利用PageHelper來實(shí)現(xiàn)。
這里講解這三種常見的實(shí)現(xiàn)方式:
無論哪種實(shí)現(xiàn)方式,我們返回的結(jié)果,不能再使用List了,需要一個(gè)自定義對(duì)象Pager。
package com.xxx.mybatis.bean;
import java.util.List;
public class Pager<T> {
private int page;//分頁起始頁
private int size;//每頁記錄數(shù)
private List<T> rows;//返回的記錄集合
private long total;//總記錄條數(shù)
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}limit關(guān)鍵字實(shí)現(xiàn)
UserDao.java增加兩個(gè)方法
public List<User> findByPager(Map<String, Object> params); public long count();
UserMapper.xml中增加兩個(gè)查詢
<select id="findByPager" resultType="com.xxx.mybatis.domain.User">
select * from xx_user limit #{page},#{size}
</select>
<select id="count" resultType="long">
select count(1) from xx_user
</select>UserService.java中增加分頁方法
public Pager<User> findByPager(int page,int size){
Map<String, Object> params = new HashMap<String, Object>();
params.put("page", (page-1)*size);
params.put("size", size);
Pager<User> pager = new Pager<User>();
List<User> list = userDao.findByPager(params);
pager.setRows(list);
pager.setTotal(userDao.count());
return pager;
}這是最直觀的實(shí)現(xiàn)方式,也是最簡(jiǎn)單的,不用任何插件或者工具就能夠很方便的實(shí)現(xiàn)的方法。
interceptor plugin實(shí)現(xiàn)
需要定義一個(gè)類實(shí)現(xiàn)Interceptor接口
MyPageInterceptor.java
package com.xxx.mybatis.bean;
import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})
public class MyPageInterceptor implements Interceptor {
private int page;
private int size;
@SuppressWarnings("unused")
private String dbType;
@SuppressWarnings("unchecked")
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("plugin is running...");
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
while(metaObject.hasGetter("h")){
Object object = metaObject.getValue("h");
metaObject = SystemMetaObject.forObject(object);
}
while(metaObject.hasGetter("target")){
Object object = metaObject.getValue("target");
metaObject = SystemMetaObject.forObject(object);
}
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
String mapId = mappedStatement.getId();
if(mapId.matches(".+ByPager$")){
ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
Map<String, Object> params = (Map<String, Object>)parameterHandler.getParameterObject();
page = (int)params.get("page");
size = (int)params.get("size");
String sql = (String) metaObject.getValue("delegate.boundSql.sql");
sql += " limit "+(page-1)*size +","+size;
metaObject.setValue("delegate.boundSql.sql", sql);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
String limit = properties.getProperty("limit","10");
this.page = Integer.parseInt(limit);
this.dbType = properties.getProperty("dbType", "mysql");
}
}我們之前在service的findByPager方法里面,為了給limit傳入兩個(gè)參數(shù),其中page做了計(jì)算,這里使用攔截器的方式就無需計(jì)算了:

public Pager<User> findByPager(int page,int size){
Map<String, Object> params = new HashMap<String, Object>();
params.put("page", page);
params.put("size", size);
Pager<User> pager = new Pager<User>();
List<User> list = userDao.findByPager(params);
pager.setRows(list);
pager.setTotal(userDao.count());
return pager;
}spring配置中,增加plugin設(shè)置:

到這里,你也許也猜到了MyPageInterceptor實(shí)際上是以一種攔截器的方式在程序執(zhí)行findByPager方法的時(shí)候,對(duì)語句會(huì)增加limit page,size的拼接,還是和第一種原生實(shí)現(xiàn)思路一樣,所以這里需要對(duì)UserMapper.xml配置文件中的findByPager這個(gè)查詢對(duì)應(yīng)的語句中的limit #{page},#{size}這部分去掉,變?yōu)槿缦碌臉幼樱?/p>

至此,通過攔截器插件的方式也實(shí)現(xiàn)了分頁功能了。
PageHelper實(shí)現(xiàn)
這種方式實(shí)現(xiàn)需要我們引入maven依賴。
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.2.1</version> </dependency>
spring.xml配置文件做一下修改:
<bean id="pageInterceptor" class="com.github.pagehelper.PageHelper"> <property name="properties"> <props> <prop key="helperDialect">mysql</prop> <prop key="reasonable">true</prop> <prop key="supportMethodsArguments">true</prop> <prop key="params">count=countSql</prop> </props> </property> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath:com/xxx/mybatis/dao/*Mapper.xml"/> <property name="plugins" ref="pageInterceptor"></property> </bean>
service層的方法,做一些修改:
public Pager<User> findByPager(int page,int size){
Pager<User> pager = new Pager<User>();
Page<User> res = PageHelper.startPage(page,size);
userDao.findAll();
pager.setRows(res.getResult());
pager.setTotal(res.getTotal());
return pager;
}至此,PageHelper工具方法實(shí)現(xiàn)分頁也實(shí)現(xiàn)了。其實(shí)PageHelper方法也是第二種使用Interceptor攔截器方式的一種三方實(shí)現(xiàn),它內(nèi)部幫助我們實(shí)現(xiàn)了Interceptor的功能。
所以我們不用自定義MyPageInterceptor這個(gè)類了。實(shí)際上也是在運(yùn)行查詢方法的時(shí)候,進(jìn)行攔截,然后設(shè)置分頁參數(shù)。
所以PageHelper.startPage(page,size)這一句需要顯示調(diào)用,然后再執(zhí)行userDao.findAll(),在查詢所有用戶信息的時(shí)候,會(huì)進(jìn)行一個(gè)分頁參數(shù)設(shè)置,讓放回的結(jié)果只是分頁的結(jié)果,而不是全部集合。
mybatis實(shí)現(xiàn)分頁查詢
使用mybatis整合時(shí),最容易遇到的需求就是分頁了,pagehelper 分頁插件是一個(gè)非常實(shí)用的 MyBatis分頁插件,可以快速的實(shí)現(xiàn)MyBatis分頁功能,而且pagehelper有個(gè)優(yōu)點(diǎn)就是分頁和Mapper.xml完全解耦,并以插件的形式實(shí)現(xiàn),有效的避免了直接寫分頁SQL語句來實(shí)現(xiàn)分頁功能
分頁插件原理
分頁插件的基本原理是使用Mybatis提供的插件接口,實(shí)現(xiàn)自定義插件,在插件的攔截方法內(nèi)攔截待執(zhí)行的sql,然后重寫sql,添加對(duì)應(yīng)的物理分頁語句和物理分頁參數(shù)
舉例:
select * from student
攔截sql后重寫為:
select t.* from (select * from student)t limit 0,10
1.引入pagehelper依賴
<dependency> ? ?<groupId>com.github.pagehelper</groupId> ? ?<artifactId>pagehelper</artifactId> ? ?<version>5.1.11</version> </dependency>
2.配置攔截器
這個(gè)是配置在mybatis-config.xml文件中
<plugins> ? ? ? ? <plugin interceptor="com.github.pagehelper.PageInterceptor"> ? ? ? ? ? ? <property name="param1" value="value1"/> ? ? ? ? </plugin> ? ? </plugins>
3.在代碼中的使用
@RequestMapping("/emps")
? ? public String list(@RequestParam(required = false,defaultValue = "1",value = "pn")Integer pn,
? ? ? ? ? ? ? ? ? ? ? ?Map<String,Object> map){
? ? ? ? //引入分頁查詢,使用PageHelper分頁功能
? ? ? ? //在查詢之前傳入當(dāng)前頁,然后多少記錄
? ? ? ? PageHelper.startPage(pn,5);
? ? ? ? //startPage后緊跟的這個(gè)查詢就是分頁查詢
? ? ? ? List<Employee> emps = employeeService.getAll();
? ? ? ? //使用PageInfo包裝查詢結(jié)果,只需要將pageInfo交給頁面就可以
? ? ? ? PageInfo pageInfo = new PageInfo<>(emps,5);
? ? ? ? //pageINfo封裝了分頁的詳細(xì)信息,也可以指定連續(xù)顯示的頁數(shù)
? ? ? ? map.put("pageInfo",pageInfo);
? ? ? ? return "list";
? ? }總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java使用Socket實(shí)現(xiàn)SMTP協(xié)議發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了java使用Socket實(shí)現(xiàn)SMTP協(xié)議發(fā)送郵件的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05
Java基于Javafaker生成測(cè)試數(shù)據(jù)
這篇文章主要介紹了Java基于Javafaker生成測(cè)試數(shù)據(jù)的方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12
關(guān)于Spring @Bean 相同加載順序不同結(jié)果不同的問題記錄
本文主要探討了在Spring 5.1.3.RELEASE版本下,當(dāng)有兩個(gè)全注解類定義相同類型的Bean時(shí),由于加載順序不同,最終生成的Bean實(shí)例也會(huì)不同,文章通過分析ConfigurationClassPostProcessor的執(zhí)行過程,解釋了BeanDefinition的加載和覆蓋機(jī)制,感興趣的朋友一起看看吧2025-02-02
詳細(xì)分析Java內(nèi)部類——局部?jī)?nèi)部類
這篇文章主要介紹了Java局部?jī)?nèi)部類的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java 內(nèi)部類的知識(shí),感興趣的朋友可以了解下2020-08-08
Spring Boot 3.5.3新特性解析及JDK21集成實(shí)戰(zhàn)應(yīng)用
Spring Boot 3.5.3作為關(guān)鍵補(bǔ)丁版本,不僅修復(fù)了此前版本中的棘手回歸問題,更深度整合JDK21特性,為高并發(fā)與云原生應(yīng)用帶來突破性提升,本文將深入解析其核心技術(shù)亮點(diǎn)及實(shí)戰(zhàn)應(yīng)用,感興趣的朋友跟隨小編一起看看吧2025-08-08

