1、前言

在前面学习mybatis的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,但是前面都是简单的案例,所以查询的数据量不是很大,自然查询时没有任何压力,但是如果在实际的项目中,数据库的数据成千上万,如果还是这样一次性查询出所有数据,那么会导致数据可读性和数据库性能极差。所以我们往往使用分页进行查询,这样对数据库压力就在可控范围内。

这里介绍Mybatis的这几种分页方式:

  1. 原生SQL的Limit分页
  2. Mybatis自带的RowBounds分页
  3. 自定义拦截器插件进行分页
  4. 使用PageHelper插件分页

下面我们来简单学习一下。

2、原生Limit分页

原生Limit分页就是在编写sql语句时需要自己加上limit关键字,然后传入分页参数进行分页,例如select * from t_user limit 0,3;

①、编写UserMapper接口

  1. /**
  2. * UserMapper接口
  3. */
  4. public interface UserMapper {
  5. //分页查询所有用户,通过原生limit
  6. List<User> selectAllUserByLimit(Map map);
  7. }

②、UserMapper.xml映射文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.thr.mapper.UserMapper">
  6.  
  7. <resultMap id="userMap" type="com.thr.pojo.User">
  8. <id property="userId" column="id"/>
  9. <result property="userName" column="username"/>
  10. <result property="userAge" column="age"/>
  11. <result property="userBirthday" column="birthday"/>
  12. <result property="userSex" column="sex"/>
  13. <result property="userAddress" column="address"/>
  14. </resultMap>
  15.  
  16. <!-- 分页查询所有用户,通过原生limit -->
  17. <select id="selectAllUserByLimit" resultMap="userMap">
  18. select * from t_user limit #{start},#{size}
  19. </select>
  20. </mapper>

③、测试分页方法

  1. //Mybatis的测试
  2. public class MybatisTest2 {
  3. //定义 SqlSession
  4. private SqlSession sqlSession = null;
  5. //定义 UserMapper对象
  6. private UserMapper mapper = null;
  7.  
  8. @Before//在测试方法执行之前执行
  9. public void getSqlSession(){
  10. //1、加载 mybatis 全局配置文件
  11. InputStream is = MybatisTest2.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
  12. //2、创建SqlSessionFactory对象
  13. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
  14. //3、根据 sqlSessionFactory 产生session
  15. sqlSession = sqlSessionFactory.openSession();
  16. //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
  17. mapper = sqlSession.getMapper(UserMapper.class);
  18. }
  19.  
  20. @After//在测试方法执行完成之后执行
  21. public void destroy() throws IOException {
  22. sqlSession.commit();
  23. sqlSession.close();
  24. }
  25. //分页查询所有用户信息,通过原生limit
  26. @Test
  27. public void selectAllUserByLimit(){
  28. int currPage = 2;//当前页码
  29. int pageSize = 3;//当前显示页记录数量
  30. HashMap<String, Object> map = new HashMap<>();
  31. //计算起始位置,注意:currPage和start别搞错了,一个表示当前页码,一个是从第几行读取记录
  32. map.put("start",(currPage-1)*pageSize);
  33. //页面显示记录数
  34. map.put("size",pageSize);
  35. System.out.println("当前页码为:第"+currPage+"页,页面显示记录数量:"+pageSize+"个");
  36. List<User> userList = mapper.selectAllUserByLimit(map);
  37. for (User user : userList) {
  38. System.out.println(user);
  39. }
  40. }
  41. }

④、运行结果

3、RowBounds分页

Mybatis内置了一个专门处理分页的类——RowBounds,我们使用它可以轻松完成分页。

RowBounds源代码如下:

  1. package org.apache.ibatis.session;
  2.  
  3. public class RowBounds {
  4. //默认值为0~~Java最大整数
  5. public static final int NO_ROW_OFFSET = 0;
  6. public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
  7. public static final RowBounds DEFAULT = new RowBounds();
  8. //偏移量,即从第几行开始读取
  9. private final int offset;
  10. //限制,即每页显示记录数量
  11. private final int limit;
  12.  
  13. public RowBounds() {
  14. this.offset = NO_ROW_OFFSET;
  15. this.limit = NO_ROW_LIMIT;
  16. }
  17. public RowBounds(int offset, int limit) {
  18. this.offset = offset;
  19. this.limit = limit;
  20. }
  21. public int getOffset() {
  22. return offset;
  23. }
  24. public int getLimit() {
  25. return limit;
  26. }
  27. }

那么我们怎样来使用这个RowBounds分页呢?非常的简单。

①、定义接口方法

  1. //分页查询所有用户,通过自带的RowBounds
  2. List<User> selectAllUserByRowBounds(RowBounds rowBounds);

②、sql映射

  1. <!-- 分页查询所有用户,通过自带的RowBounds -->
  2. <select id="selectAllUserByRowBounds" resultMap="userMap">
  3. select * from t_user
  4. </select>

使用RowBounds分页我们可以不写在映射SQL中写limit关键字,到时候自动回给我们拼接。就两个字,方便!

③、测试方法

  1. //分页查询所有用户信息,通过自带的RowBounds
  2. @Test
  3. public void selectAllUserByRowBounds(){
  4. int currPage=2;//当前页码
  5. int pageSize=3;//当前页显示记录数量
  6. //注意:currPage和start别搞错了,一个表示当前页码,一个是从第几行读取记录
  7. int start = (currPage-1)*pageSize;//计算从第几行读取记录
  8. RowBounds rowBounds = new RowBounds(start,pageSize);
  9. List<User> userList = mapper.selectAllUserByRowBounds(rowBounds);
  10. for (User user : userList) {
  11. System.out.println(user);
  12. }
  13. }

④、运行结果

RowBounds分页有一点好处就是处理数据量少时还可以,但是数据量大时,就不行好用了,此时一般都会实现拦截器来完成分页。

4、自定义拦截器插件分页

自定义拦截器插件分页 需要自己定义一个类实现Interceptor接口,这个接口是Mybatis提供的。任何分页插件想要对Mybatis进行分页就必须实现Interceptor接口,包括后面PageHelper分页插件。

①、创建MyPageInterceptor类

  1. /**
  2. * @Intercepts 表示是一个拦截器
  3. * @Signature 拦截器的签名
  4. * type 拦截的类型 四大对象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
  5. * method 拦截的方法
  6. */
  7. @Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class, Integer.class })})
  8. public class MyPageInterceptor implements Interceptor {
  9.  
  10. //当前页码
  11. private int currPage;
  12. //每页显示的条目数
  13. private int pageSize;
  14. //数据库类型
  15. private String dbType;
  16.  
  17. @Override
  18. public Object intercept(Invocation invocation) throws Throwable {
  19. System.out.println("plugin is running...");
  20. //获取StatementHandler,默认是RoutingStatementHandler
  21. StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
  22. //获取statementHandler包装类
  23. MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);
  24.  
  25. //分离代理对象链
  26. while (MetaObjectHandler.hasGetter("h")) {
  27. Object obj = MetaObjectHandler.getValue("h");
  28. MetaObjectHandler = SystemMetaObject.forObject(obj);
  29. }
  30.  
  31. while (MetaObjectHandler.hasGetter("target")) {
  32. Object obj = MetaObjectHandler.getValue("target");
  33. MetaObjectHandler = SystemMetaObject.forObject(obj);
  34. }
  35.  
  36. //获取连接对象
  37. //Connection connection = (Connection) invocation.getArgs()[0];
  38. //object.getValue("delegate"); 获取StatementHandler的实现类
  39.  
  40. //获取查询接口映射的相关信息
  41. MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
  42. String mapId = mappedStatement.getId();
  43.  
  44. //statementHandler.getBoundSql().getParameterObject();
  45.  
  46. //拦截以.ByPage结尾的请求,分页功能的统一实现
  47. if (mapId.matches(".+ByPage$")) {
  48. //获取进行数据库操作时管理参数的handler
  49. ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
  50. //获取请求时的参数
  51. Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
  52. //也可以这样获取
  53. //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();
  54.  
  55. //参数名称和在service中设置到map中的名称一致
  56. currPage = (int) paraObject.get("currPage");
  57. pageSize = (int) paraObject.get("pageSize");
  58.  
  59. String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
  60. //也可以通过statementHandler直接获取
  61. //sql = statementHandler.getBoundSql().getSql();
  62.  
  63. //构建分页功能的sql语句
  64. String limitSql;
  65. sql = sql.trim();
  66. limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;
  67.  
  68. //将构建完成的分页sql语句赋值个体'delegate.boundSql.sql',偷天换日
  69. MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
  70. }
  71. //调用原对象的方法,进入责任链的下一级
  72. return invocation.proceed();
  73. }
  74.  
  75. //获取代理对象
  76. @Override
  77. public Object plugin(Object o) {
  78. //生成object对象的动态代理对象
  79. return Plugin.wrap(o, this);
  80. }
  81.  
  82. //设置代理对象的参数
  83. @Override
  84. public void setProperties(Properties properties) {
  85. //如果项目中分页的pageSize是统一的,也可以在这里统一配置和获取,这样就不用每次请求都传递pageSize参数了。参数是在配置拦截器时配置的。
  86. String limit1 = properties.getProperty("limit", "10");
  87. this.pageSize = Integer.valueOf(limit1);
  88. this.dbType = properties.getProperty("dbType", "mysql");
  89. }
  90. }

②、全局配置文件增加plugin设置(注意位置)

  1. <!-- 配置自定义分页插件 -->
  2. <plugins>
  3. <plugin interceptor="com.thr.interceptor.MyPageInterceptor">
  4. </plugin>
  5. </plugins>

③、接口方法

  1. //分页查询所有用户,通过原生自定义拦截器
  2. List<User> selectAllUserByPage(Map map);

由于拦截器中设置了拦截以.ByPage结尾的方法,所以方法一定要命名正确,

④、sql映射

  1. <!-- 分页查询所有用户,通过自定义拦截器 -->
  2. <select id="selectAllUserByPage" resultMap="userMap">
  3. select * from t_user
  4. </select>

⑤、测试方法

5、PageHelper分页插件

PageHelper是一款非常优秀的分页插件,用的人非常多,详细的可以参考PageHelper的官方文档,讲的比较通俗易懂。链接:https://pagehelper.github.io/docs/howtouse/。 PageHelper分页其实也是自定义拦截器方式的一种第三方实现,它内部帮助我们实现了Interceptor的功能。所以实际上我们在执行查询方法之前,PageHelper分页插件同样是对我们的 sql 进行拦截,然后对分页参数进行拼接。

PageHelper的简单使用:

①、引入PageHelper依赖:

  1. <!-- pagehelper分页插件 -->
  2. <dependency>
  3. <groupId>com.github.pagehelper</groupId>
  4. <artifactId>pagehelper</artifactId>
  5. <version>5.2.0</version>
  6. </dependency>

②、全局配置文件增加plugin设置(注意位置)

  1. <!-- 配置分页插件 -->
  2. <plugins>
  3. <!-- PageHelper5版本配置 -->
  4. <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
  5. </plugins>

③、接口方法

  1. //分页查询所有用户,通过PageHelper
  2. List<User> selectAllUserByPageHelper();

④、sql映射

  1. <!-- 分页查询所有用户,通过PageHelper -->
  2. <select id="selectAllUserByPageHelper" resultMap="userMap">
  3. select * from t_user
  4. </select>

⑤、测试方法

  1. //分页查询所有用户信息,通过PageHelper
  2. @Test
  3. public void selectAllUserByPageHelper(){
  4. int currPage = 2;//当前页码
  5. int pageSize = 3;//当前页记录数量
  6. //表示获取第2页,3条内容,默认会查询总数count
  7. PageHelper.startPage(currPage,pageSize);
  8. List<User> userList = mapper.selectAllUserByPageHelper();
  9. for (User user : userList) {
  10. System.out.println(user);
  11. }
  12. }

⑥、运行结果

以上只是PageHelper的简单介绍,还有更多的功能可以去参考官方文档,也可以自行百度学习。

Mybatis3详解(十四)----Mybatis的分页的更多相关文章

  1. Linux学习之用户配置文件详解(十四)

    Linux学习之用户配置文件详解 目录 用户信息文件/etc/password 影子文件/etc/shadow 组信息文件/etc/group 组密码文件/etc/gshadow 用户信息文件/etc ...

  2. Nginx详解十四:Nginx场景实践篇之代理服务

    代理的作用 Nginx代理 正向代理 反向代理 正向代理和反向代理的区别:代理的对象不一样 正向代理代理的对象是客户端,反向代理代理的对象是服务端 反向代理: 配置语法:proxy_pass URL; ...

  3. Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节

    简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...

  4. ViewPager 详解(四)----自主实现滑动指示条

    前言:前面我们用了三篇的时间讲述了有关ViewPager的基础知识,到这篇就要进入点实际的了.在第三篇<ViewPager 详解(三)---PagerTabStrip与PagerTitleStr ...

  5. spring事务详解(四)测试验证

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  6. RocketMQ详解(四)核心设计原理

    专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...

  7. OutputCache属性详解(四)— SqlDependency

    目录 OutputCache概念学习 OutputCache属性详解(一) OutputCache属性详解(二) OutputCache属性详解(三) OutputCache属性详解(四)— SqlD ...

  8. IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构(转载)

    IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构 系列文章链接: IIS负载均衡-Application Request Route详解第一篇: ...

  9. 前端技术之_CSS详解第四天

    前端技术之_CSS详解第四天 一.第三天的小总结 盒模型box model,什么是盒子? 所有的标签都是盒子.无论是div.span.a都是盒子.图片.表单元素一律看做文本. 盒模型有哪些组成: wi ...

  10. Keepalived详解(四):通过vrrp_script实现对集群资源的监控【转】

    一.通过vrrp_script实现对集群资源的监控: Keepalived基础HA功能时用到了vrrp_script这个模块,此模块专门用于对集群中服务资源进行监控.与此模块一起使用的还有track_ ...

随机推荐

  1. Day07_37_深度剖析集合中的contains()方法

    深度剖析集合中的 contains()方法 contains()方法查找集合中是否包含某个元素 contains() 底层使用的是 equals()方法 当contains()方法拿到一个对象的时候, ...

  2. 什么是SQL注入漏洞?

    什么是SQL注入: SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL. SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字 ...

  3. k8s 安装 rabbitMQ 单机版

    rabbitMQ docker镜像使用rabbitmq:3.8-management service.yaml文件 apiVersion: v1 kind: Service metadata: nam ...

  4. 数据分析处理之PCA OLSR PCR PLSR(NIPALS)及其Matlab代码实现

    传统的OLS(普通最小二乘)方法无法解决样本数据的共线性(multicollinearity)问题,如果你的数据样本中每个特征变量具有共线性,那么使用基于PCA的PCR和PLSR方法对数据样本进行回归 ...

  5. hdu1024 最大m子序列和

    题意:      给你一个序列n个数组成,然后让你在里面找到m个子序列,让这m个子序列的和最大. 思路:       dp[i][j]表示的是第j个数字在第i个子序列时的当前最优值. dp[i][j] ...

  6. hdu4930 模拟斗地主

    题意:        模拟斗地主,出牌有一下规则,1张,1对,3张,3带1,3带2,炸弹(包括两个猫),4带2,这写规则,没有其他的,然后给你两幅牌,只要第一个人出了一次牌对方管不上,那么或者第一个人 ...

  7. 神经网络与机器学习 笔记—多层感知器(MLP)

    多层感知器(MLP) Rosenblatt感知器和LMS算法,都是单层的并且是单个神经元构造的神经网络,他们的局限性是只能解决线性可分问题,例如Rosenblatt感知器一直没办法处理简单异或问题.然 ...

  8. xxl-job滥用netty导致的问题和解决方案

    netty作为一种高性能的网络编程框架,在很多开源项目中大放异彩,十分亮眼,但是在有些项目中却被滥用,导致使用者使用起来非常的难受. 本篇文章将会讲解xxl-job作为一款分布式任务调度系统是如何滥用 ...

  9. HR:“最喜欢阿里出来的程序员了,技术又好又耐艹!” 我:???

    面试造火箭,进厂拧螺丝?真的是这样吗? 缘起 估计不少同学都是被标题吸引进来的.事先声明,这句话不是我虚构的,而是我实实在在从同事的口中听到的,而且还不止一次. 当时的场景就是很正常的交谈,别人也并没 ...

  10. 将HTML字符串编译为虚拟DOM对象的基础实现

    本文所有代码均保存在HouyunCheng / mini-2vdom 虚拟DOM只是实现MVVM的一种方案,或者说是视图更新的一种策略,是实现最小化更新的diff算法的操作对象. 创建扫描器 所有编译 ...