Mybatis使用之分页

Mybatis使用之分页

一:简介

注:示例基于mysql数据库。Oracle可以自行测试。

 

使用Mybatis分页主要有两种方式、一种是将分页参数传递到配置文件中、在写sql的时候就做分页。另一种是使用Mybatis的拦截器拦截需要分页的sql语句、重新组装成具有分页功能的sql语句。

分页查询的关键在于查询时需要告诉数据库从第几条开始取、取多少条记录。也就是常用到Page对象(一般是方便传递参数、自己构建的实体类)的pageNumer、pageSize两个主要参数。至于Page对象的总记录数等是需要带到前台构造数据展示表格时使用的参数。

二:传递参数形式的分页

2.1 关键点

传递参数形式的分页就是将分页信息以参数的形式传递到映射文件中、这样就可以在编写具体的sql语句时实现分页功能。这种方式的重点在于一般的查询语句都会带有一个或者多个查询参数、而‘select‘标签的parameterType只能接收一个值。所以需要我们将查询参数与分页参数组装成一个Map作为参数传递到映射语句中。

不过前台展示所需要的数据总数还需要另写一条count查询语句来获取。多多少少会有些不便。

2.2 具体代码

映射文件:

   <select id="selectAuthorWithPageParam"resultType="author" parameterType="hashMap">

       SELECT

           t.id,

           t.username,

           t.password,

           t.email,

           t.bio,

           t.favourite_section favouriteSection

       FROM author t

       WHERE t.username = {username} AND t.password = {password} limit {page.dbIndex},{page.dbNumber}

   </select>

映射接口:

   List<Author> selectAuthorWithPageParam(Map<String, Object>map);

测试代码:

   @Test

   public void testSelectAuthorWithPageParam() throws Exception {

       Page page = new Page();

       page.count();

       Map<String, Object> map = new HashMap<>();

       map.put("page", page);

       map.put("username", "alien");

        map.put("password","alien");

       List<Author> authors =this.authorMapper.selectAuthorWithPageParam(map);

       Assert.assertEquals(5, authors.size());

    }

三:拦截器分页

3.1 关键点

拦截器实现分页的关键之处在于、在需要分页的sql语句执行之前、拦截下来并改造成具有分页功能的sql语句(还可以查询一下总数、设置到Page实体类中供前台展示数据时使用)、然后继续执行。

3.2 具体代码

说起来很简单、但是短短的一句话却需要理解许多东西才能达到目的。这里只挑一些重点步骤、具体拦截器工作原理、执行过程会在Mybatis深入过程详细分析。

从使用角度来考虑过程如下(***对所有映射语句id以‘ByPage‘结尾的做分页处理***):

3.2.1 Page实体类:

package org.alien.mybatis.samples.entity;

/**

 *Created by andy on 5/25/2015.<br>

 *Version 1.0-SNAPSHOT<br>

 */

@SuppressWarnings("unused")

public class Page {

   /**

    * 总条数

    */

   private int totalNumber;

   /**

    * 当前第几页

    */

   private int currentPage;

   /**

    * 总页数

    */

   private int totalPage;

   /**

    * 每页显示条数

    */

   private int pageNumber = 5;

   /**

    * 数据库中limit的参数,从第几条开始取

    */

   private int dbIndex;

   /**

    * 数据库中limit的参数,一共取多少条

    */

   private int dbNumber;

   /**

    * Oracle 起始记录行号

    */

   private int rowNum;

   /**

    * Oracle 结束记录行号

    */

   private int rn;

   /**

    * 根据当前对象中属性值计算并设置相关属性值

    */

   public void count() {

       // 计算总页数

       int totalPageTemp = this.totalNumber / this.pageNumber;

       int plus = (this.totalNumber % this.pageNumber) == 0 ? 0 : 1;

       totalPageTemp = totalPageTemp + plus;

       if(totalPageTemp <= 0) {

           totalPageTemp = 1;

       }

        this.totalPage = totalPageTemp;

       // 设置当前页数

       // 总页数小于当前页数,应将当前页数设置为总页数

       if(this.totalPage < this.currentPage) {

           this.currentPage = this.totalPage;

       }

       // 当前页数小于1设置为1

       if(this.currentPage < 1) {

           this.currentPage = 1;

       }

       // 设置limit的参数

       this.dbIndex = (this.currentPage - 1) * this.pageNumber;

       this.dbNumber = this.pageNumber;

    }

   public int getTotalNumber() {

       return totalNumber;

    }

   public void setTotalNumber(int totalNumber) {

       this.totalNumber = totalNumber;

       this.count();

    }

   public int getCurrentPage() {

       return currentPage;

    }

   public void setCurrentPage(int currentPage) {

       this.currentPage = currentPage;

    }

   public int getTotalPage() {

       return totalPage;

    }

   public void setTotalPage(int totalPage) {

       this.totalPage = totalPage;

    }

   public int getPageNumber() {

       return pageNumber;

    }

   public void setPageNumber(int pageNumber) {

       this.pageNumber = pageNumber;

       this.count();

    }

   public int getDbIndex() {

       return dbIndex;

    }

   public void setDbIndex(int dbIndex) {

       this.dbIndex = dbIndex;

    }

   public int getDbNumber() {

       return dbNumber;

    }

   public void setDbNumber(int dbNumber) {

       this.dbNumber = dbNumber;

    }

   public int getRn() {

       return (this.getCurrentPage() + 1) * this.getPageNumber();

    }

   public void setRn(int rn) {

       this.rn = rn;

    }

   public int getRowNum() {

       return this.getCurrentPage() * this.getPageNumber();

    }

   public void setRowNum(int rowNum) {

       this.rowNum = rowNum;

    }

3.2.2 拦截器类:

packageorg.alien.mybatis.samples.interceptor;

importorg.alien.mybatis.samples.entity.Page;

importorg.apache.ibatis.executor.parameter.ParameterHandler;

importorg.apache.ibatis.executor.statement.StatementHandler;

import org.apache.ibatis.mapping.BoundSql;

importorg.apache.ibatis.mapping.MappedStatement;

import org.apache.ibatis.plugin.*;

importorg.apache.ibatis.reflection.MetaObject;

importorg.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.util.Map;

import java.util.Properties;

/**

 *Page interceptor.

 *Support oracle and mysql.

 *Created by andy on 5/25/2015.<br>

 *Version 1.0-SNAPSHOT<br>

 */

@Intercepts({@Signature(type =StatementHandler.class, method = "prepare", args ={Connection.class})})

public class PageInterceptor implementsInterceptor {

   private String dialect;

   @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");

       String sqlId = mappedStatement.getId();

       //intercept select sql witch end with "ByPage".

       if (sqlId.matches(".+ByPage$")) {

           BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");

           String sql = boundSql.getSql();

           ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");

           Map<?, ?> paramMap = (Map<?, ?>)parameterHandler.getParameterObject();

           Page page = (Page) paramMap.get("page");

           //set count

           Connection connection = (Connection) invocation.getArgs()[0];

           String countSql = "select count(1) from (" + sql + ")a";

           PreparedStatement preparedStatement =connection.prepareStatement(countSql);

           parameterHandler.setParameters(preparedStatement);

           ResultSet resultSet = preparedStatement.executeQuery();

           if (resultSet.next()) {

               page.setTotalNumber(resultSet.getInt(1));

           }

           //construct record limit sql by dialect

           String pageSql;

           if ("oracle".equals(dialect.toLowerCase())) {

                pageSql = "select * from" +

                        "(select a.*,rownum rn from (" + sql + ") a where rownum >= " +page.getRowNum() + ") " +

                        "rn < " +page.getRn();

           } else if ("mysql".equals(dialect.toLowerCase())) {

                pageSql = sql + " limit" + page.getDbIndex() + "," + page.getDbNumber();

           } else {

                pageSql = 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.dialect = properties.getProperty("dialect");

    }
}

3.2.3 mybatis.xml总配置文件中注册拦截器

***注意Mybatis配置文件各个元素的顺序!***          

   <plugins>

       <plugin interceptor="org.alien.mybatis.samples.interceptor.PageInterceptor">

           <!--database dialect, only support mysql and oracle-->

           <property name="dialect" value="mysql"/>

       </plugin>

   </plugins>

3.2.4 映射文件语句

   <select id="selectAuthorByPage" resultType="author"parameterType="hashMap">

       SELECT

           t.id,

           t.username,

           t.password,

           t.email,

           t.bio,

           t.favourite_section favouriteSection

       FROM author t

       WHERE t.username = {username} AND t.password = {password}

   </select>

3.2.4 映射接口方法

   List<Author> selectAuthorByPage(Map<String, Object> map);

3.2.4 测试方法

   @Test

   public void testSelectAuthorByPage() throws Exception {

       Page page = new Page();

       Map<String, Object> map = new HashMap<>();

       map.put("page", page);

       List<Author> authors = this.authorMapper.selectAuthorByPage(map);

       Assert.assertEquals(5, authors.size());

    }

三:补充

更多内容:Mybatis 目录

篇幅有限、仅仅说明了拦截器的实现过程、原理及代码都没有详细说明、这些会在Mybatis深入中详细解析。

时间: 2024-10-09 18:30:38

Mybatis使用之分页的相关文章

Mybatis Generator实现分页功能

Mybatis Generator实现分页功能 分类: IBATIS2013-07-17 17:03 882人阅读 评论(1) 收藏 举报 mybatisibatisgeneratorpage分页 众所周知,Mybatis本身没有提供基于数据库方言的分页功能,而是基于JDBC的游标分页,很容易出现性能问题.网上有很多分页的解决方案,不外乎是基于Mybatis本机的插件机制,通过拦截Sql做分页.但是在像Oracle这样的数据库上,拦截器生成的Sql语句没有变量绑定,而且每次语句的都要去拦截,感觉

Mybatis最入门---分页查询(拦截器分页原理及实现)

[一步是咫尺,一步即天涯] 前文,我们演示了物理分页的Sql实现方式,这种方式使得我们每次在编写查询服务时,不断的重复造轮子.这样的代码实现方式就显得十分的笨拙了.本文是Mybatis分页查询的最后一片内容,我们将介绍基于拦截器的,精巧的实现方式.在阅读这篇文章之前,强烈建议各位看官能够先阅读上文.这样就能对下文我们提及的各种对象及他们之间的关系有一个清晰的关系.好了,废话不多讲,开始我们的正文部分吧. 准备工作: a.操作系统 :win7 x64 b.基本软件:MySQL,Mybatis,SQ

SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页

SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了.全部自动实现. 话不多说,直接上代码: 第一步pom文件配置添加jar: <!-- mybatis的分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>

小白的springboot之路(十五)、mybatis的PageHelper分页插件使用

0.前言 用mybatis,那么分页必不可少,基本都是用PageHelper这个分页插件,好用方便: 1.实现 1.1.添加依赖: <!-- 3.集成 mybatis pagehelper--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version

MyBatis 杂项(分页,缓存,处理BLOB\CLOB数据)

1.处理CLOB,BLOB数据 oracle中的 clob:clob blob:blobmysql中的 clob:longtext blob:longblob 2.传入多个输入参数,mybatis自带的param属性(但是不经常用,我们用map就足够了) 3.MyBatis分页 逻辑分页:将数据全部取出先放到内存中,之后在内存中进行分页,性能不好.不推荐使用 物理分页:通过语句进行分页. 4.MyBatis缓存 MyBatis默认情况下:MyBatis默认使用一级缓存,即同一个SqlSessio

mybatis如何做分页处理

1.首先根据自己实际需求编写实体类 1 import java.io.Serializable; 2 3 public class User implements Serializable{ //最好将该实体类序列化 4 5 private static final long serialVersionUID = 1L; 6 7 private Integer id; 8 private String name; 9 private String birthday; 10 private Str

mybatis多表分页

mybatis的分页是通过拦截器重新拼接SQL,因此分页语句基本都是包含在整个SQL语句外面,那么对于多表查询就会出现查询结果不准确的结果,A与B为一对多关系,A为主表,当使用链接语句查询A和B时,由于A对应的B可能有多条,因此实际的结果是结果集小于A表查询的结果集,采用如下解决方式: 先通过group by id 得到A表的正确的数据集的ID,然后再降得到的ID作为条件再次查找得到数据集 select a.id from A a left join B b on b.no = a.no whe

mybatis常用经典分页方法

来自棱镜学院-在线IT教育www.prismcollege.com 分页方法一: 可以查看如下代码,新建一个数据库分页基础类 package com.ssm.utils.pagination.pagebounds; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spr

SpringMVC+MyBatis+EasyUI 实现分页查询

user_list.jsp <%@ page import="com.ssm.entity.User" %> <%@ page pageEncoding="UTF-8" import="java.util.List" %> <html> <head> <%@ include file="meta.jsp" %> <meta charset="UTF-8