MyBatis分页插件的使用(1)--PageHelper

前言

`在mysql中,分页的sql是使用limit来做的。但是一旦model多了起来,那么就很难维护了。而使用分页插件PageHelper正好可以解决这一问题。
分页插件PageHelper是通过mybatis的拦截器实现分页功能的,拦截sql查询请求,添加分页语句,最终实现分页查询功能。

一、分页插件PageHelper支持的数据库类型?

Oracle,MySql,MariaDB,SQLite等

二、分页插件PageHelper的原理

一次请求就是一个线程,PageHelper.startPage(page,size)中携带分页参数。分页参数会设置在ThreadLocal中。PageHelper会在mybatis执行sql前进行拦截,从ThreadLocal中取出分页参数,修改当前执行的sql语句,添加分页sql,最后执行了添加了分页的sql语句,实现分页查询
在这里插入图片描述

三、分页插件PageHelper的使用原理

1.在springboot的应用程序中引入依赖(pom.xml)
在这里插入图片描述
2.sql
在这里插入图片描述
在这里插入图片描述
3.java代码
在这里插入图片描述
PageInfo这个类里边的参数:
在这里插入图片描述
在这里插入图片描述

总结

PageInterceptor.java:
package cn.wangh.page;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
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.BoundSql;
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;

import cn.wangh.model.Page;

/**

  • 分页拦截器
    */
    @Intercepts({@Signature(type=StatementHandler.class,method=“prepare”,args={Connection.class})})
    public class PageInterceptor implements Interceptor {

    private String databaseType;// 数据库类型,不同的数据库有不同的分页方法

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
    MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY);
    MappedStatement mappedStatement = (MappedStatement)metaObject.getValue(“delegate.mappedStatement”);
    // 配置文件中SQL语句的ID
    String id = mappedStatement.getId();
    if(id.matches(".+ByPage$")) {
    BoundSql boundSql = statementHandler.getBoundSql();
    // 原始的SQL语句
    String sql = boundSql.getSql();
    // 查询总条数的SQL语句
    String countSql = “select count(*) from (” + sql + “) table_count”;
    Connection connection = (Connection)invocation.getArgs()[0];
    PreparedStatement countStatement = connection.prepareStatement(countSql);
    // 通过反射获取到当前ParameterHandler对象的delegate属性
    ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue(“delegate.parameterHandler”);
    parameterHandler.setParameters(countStatement);
    ResultSet rs = countStatement.executeQuery();

         Map<?,?> parameter = (Map<?,?>)boundSql.getParameterObject();
         Page page = (Page)parameter.get("page");
         if(rs.next()) {
             page.setTotalNumber(rs.getInt(1));
         }
         // 改造后带分页查询的SQL语句
    

// String pageSql = sql + " limit " + page.getDbIndex() + “,” + page.getDbNumber();
String pageSql = getPageSql(page, sql);
metaObject.setValue(“delegate.boundSql.sql”, pageSql);
}
return invocation.proceed();
}

@Override
public Object plugin(Object target) {
    return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {
     this.databaseType = properties.getProperty("databaseType");
}
 /**
 * 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle 其它的数据库都没有进行分页
 */
 private String getPageSql(Page page, String sql) {
     final StringBuffer sqlBuffer = new StringBuffer(sql);
        if ("mysql".equalsIgnoreCase(databaseType)) {
            return getMysqlPageSql(page, sqlBuffer);
        } else if ("oracle".equalsIgnoreCase(databaseType)) {
            return getOraclePageSql(page, sqlBuffer);
        }
        return sqlBuffer.toString();
}
 /**
  * 获取Oracle数据库的分页查询语句
  */
private String getOraclePageSql(Page page, StringBuffer sqlBuffer) {
     // 计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的
    final int offset = (page.getCurrentPage() - 1) * page.getDbNumber() + 1;
    sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u where rownum < ")
            .append(offset + page.getDbNumber());
    sqlBuffer.insert(0, "select * from (").append(") where r >= ").append(offset);
    // 上面的Sql语句拼接之后大概是这个样子:
    // select * from (select u.*, rownum r from (select * from t_user) u
    // where rownum < 31) where r >= 16
    return sqlBuffer.toString();
}
 /**
 * 获取Mysql数据库的分页查询语句
 */
private String getMysqlPageSql(Page page, StringBuffer sqlBuffer) {
    // 计算第一条记录的位置,Mysql中记录的位置是从0开始的。
    sqlBuffer.append(" limit ").append(page.getDbIndex()).append(",").append(page.getDbNumber());
    return sqlBuffer.toString();
}

}

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于使用 MyBatis 分页件 PageHelper,可以参考以下步骤: 1. 在项目的 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> ``` 2. 在 MyBatis 配置文件中配置 PageHelper 件: ```xml <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!--数据库类型,mybatis会根据不同的数据库使用不同的分页策略--> <property name="helperDialect" value="mysql"/> <!--参数映射,不设置该参数时使用默认值--> <property name="reasonable" value="true"/> </plugin> </plugins> ``` 3. 在代码中使用 PageHelper.startPage 方法设置分页查询: ```java // pageNum:当前页码,pageSize:每页显示条数 PageHelper.startPage(pageNum, pageSize); // 调用 MyBatis 的查询方法,会自动实现分页 List<User> userList = userDao.queryUsers(); ``` 4. 在页面中显示分页信息和查询结果: ```html <!-- pageInfo 是 PageHelper 返回的分页信息 --> <nav> <ul class="pagination"> <li><a href="${pageInfo.prePage}">上一页</a></li> <li><a href="${pageInfo.nextPage}">下一页</a></li> </ul> </nav> <!-- userList 是上述查询返回的结果 --> <table> <thead> <tr> <th>编号</th> <th>用户名</th> <th>邮箱</th> <th>手机号码</th> </tr> </thead> <tbody> <c:forEach items="${userList}" var="user"> <tr> <td>${user.id}</td> <td>${user.username}</td> <td>${user.email}</td> <td>${user.mobile}</td> </tr> </c:forEach> </tbody> </table> ``` 希望这份简单的使用说明能够帮到你,如果有其它问题,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值