Mybatis3详解(十四)----Mybatis的分页
1、前言
在前面学习mybatis的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,但是前面都是简单的案例,所以查询的数据量不是很大,自然查询时没有任何压力,但是如果在实际的项目中,数据库的数据成千上万,如果还是这样一次性查询出所有数据,那么会导致数据可读性和数据库性能极差。所以我们往往使用分页进行查询,这样对数据库压力就在可控范围内。
这里介绍Mybatis的这几种分页方式:
- 原生SQL的Limit分页
- Mybatis自带的RowBounds分页
- 自定义拦截器插件进行分页
- 使用PageHelper插件分页
下面我们来简单学习一下。
2、原生Limit分页
原生Limit分页就是在编写sql语句时需要自己加上limit关键字,然后传入分页参数进行分页,例如select * from t_user limit 0,3;
①、编写UserMapper接口
- /**
- * UserMapper接口
- */
- public interface UserMapper {
- //分页查询所有用户,通过原生limit
- List<User> selectAllUserByLimit(Map map);
- }
②、UserMapper.xml映射文件
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.thr.mapper.UserMapper">
- <resultMap id="userMap" type="com.thr.pojo.User">
- <id property="userId" column="id"/>
- <result property="userName" column="username"/>
- <result property="userAge" column="age"/>
- <result property="userBirthday" column="birthday"/>
- <result property="userSex" column="sex"/>
- <result property="userAddress" column="address"/>
- </resultMap>
- <!-- 分页查询所有用户,通过原生limit -->
- <select id="selectAllUserByLimit" resultMap="userMap">
- select * from t_user limit #{start},#{size}
- </select>
- </mapper>
③、测试分页方法
- //Mybatis的测试
- public class MybatisTest2 {
- //定义 SqlSession
- private SqlSession sqlSession = null;
- //定义 UserMapper对象
- private UserMapper mapper = null;
- @Before//在测试方法执行之前执行
- public void getSqlSession(){
- //1、加载 mybatis 全局配置文件
- InputStream is = MybatisTest2.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
- //2、创建SqlSessionFactory对象
- SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
- //3、根据 sqlSessionFactory 产生session
- sqlSession = sqlSessionFactory.openSession();
- //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
- mapper = sqlSession.getMapper(UserMapper.class);
- }
- @After//在测试方法执行完成之后执行
- public void destroy() throws IOException {
- sqlSession.commit();
- sqlSession.close();
- }
- //分页查询所有用户信息,通过原生limit
- @Test
- public void selectAllUserByLimit(){
- int currPage = 2;//当前页码
- int pageSize = 3;//当前显示页记录数量
- HashMap<String, Object> map = new HashMap<>();
- //计算起始位置,注意:currPage和start别搞错了,一个表示当前页码,一个是从第几行读取记录
- map.put("start",(currPage-1)*pageSize);
- //页面显示记录数
- map.put("size",pageSize);
- System.out.println("当前页码为:第"+currPage+"页,页面显示记录数量:"+pageSize+"个");
- List<User> userList = mapper.selectAllUserByLimit(map);
- for (User user : userList) {
- System.out.println(user);
- }
- }
- }
④、运行结果
3、RowBounds分页
Mybatis内置了一个专门处理分页的类——RowBounds,我们使用它可以轻松完成分页。
RowBounds源代码如下:
- package org.apache.ibatis.session;
- public class RowBounds {
- //默认值为0~~Java最大整数
- public static final int NO_ROW_OFFSET = 0;
- public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
- public static final RowBounds DEFAULT = new RowBounds();
- //偏移量,即从第几行开始读取
- private final int offset;
- //限制,即每页显示记录数量
- private final int limit;
- public RowBounds() {
- this.offset = NO_ROW_OFFSET;
- this.limit = NO_ROW_LIMIT;
- }
- public RowBounds(int offset, int limit) {
- this.offset = offset;
- this.limit = limit;
- }
- public int getOffset() {
- return offset;
- }
- public int getLimit() {
- return limit;
- }
- }
那么我们怎样来使用这个RowBounds分页呢?非常的简单。
①、定义接口方法
- //分页查询所有用户,通过自带的RowBounds
- List<User> selectAllUserByRowBounds(RowBounds rowBounds);
②、sql映射
- <!-- 分页查询所有用户,通过自带的RowBounds -->
- <select id="selectAllUserByRowBounds" resultMap="userMap">
- select * from t_user
- </select>
使用RowBounds分页我们可以不写在映射SQL中写limit关键字,到时候自动回给我们拼接。就两个字,方便!
③、测试方法
- //分页查询所有用户信息,通过自带的RowBounds
- @Test
- public void selectAllUserByRowBounds(){
- int currPage=2;//当前页码
- int pageSize=3;//当前页显示记录数量
- //注意:currPage和start别搞错了,一个表示当前页码,一个是从第几行读取记录
- int start = (currPage-1)*pageSize;//计算从第几行读取记录
- RowBounds rowBounds = new RowBounds(start,pageSize);
- List<User> userList = mapper.selectAllUserByRowBounds(rowBounds);
- for (User user : userList) {
- System.out.println(user);
- }
- }
④、运行结果
RowBounds分页有一点好处就是处理数据量少时还可以,但是数据量大时,就不行好用了,此时一般都会实现拦截器来完成分页。
4、自定义拦截器插件分页
自定义拦截器插件分页 需要自己定义一个类实现Interceptor接口,这个接口是Mybatis提供的。任何分页插件想要对Mybatis进行分页就必须实现Interceptor接口,包括后面PageHelper分页插件。
①、创建MyPageInterceptor类
- /**
- * @Intercepts 表示是一个拦截器
- * @Signature 拦截器的签名
- * type 拦截的类型 四大对象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
- * method 拦截的方法
- */
- @Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class, Integer.class })})
- public class MyPageInterceptor implements Interceptor {
- //当前页码
- private int currPage;
- //每页显示的条目数
- private int pageSize;
- //数据库类型
- private String dbType;
- @Override
- public Object intercept(Invocation invocation) throws Throwable {
- System.out.println("plugin is running...");
- //获取StatementHandler,默认是RoutingStatementHandler
- StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
- //获取statementHandler包装类
- MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);
- //分离代理对象链
- while (MetaObjectHandler.hasGetter("h")) {
- Object obj = MetaObjectHandler.getValue("h");
- MetaObjectHandler = SystemMetaObject.forObject(obj);
- }
- while (MetaObjectHandler.hasGetter("target")) {
- Object obj = MetaObjectHandler.getValue("target");
- MetaObjectHandler = SystemMetaObject.forObject(obj);
- }
- //获取连接对象
- //Connection connection = (Connection) invocation.getArgs()[0];
- //object.getValue("delegate"); 获取StatementHandler的实现类
- //获取查询接口映射的相关信息
- MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
- String mapId = mappedStatement.getId();
- //statementHandler.getBoundSql().getParameterObject();
- //拦截以.ByPage结尾的请求,分页功能的统一实现
- if (mapId.matches(".+ByPage$")) {
- //获取进行数据库操作时管理参数的handler
- ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
- //获取请求时的参数
- Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
- //也可以这样获取
- //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();
- //参数名称和在service中设置到map中的名称一致
- currPage = (int) paraObject.get("currPage");
- pageSize = (int) paraObject.get("pageSize");
- String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
- //也可以通过statementHandler直接获取
- //sql = statementHandler.getBoundSql().getSql();
- //构建分页功能的sql语句
- String limitSql;
- sql = sql.trim();
- limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;
- //将构建完成的分页sql语句赋值个体'delegate.boundSql.sql',偷天换日
- MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
- }
- //调用原对象的方法,进入责任链的下一级
- return invocation.proceed();
- }
- //获取代理对象
- @Override
- public Object plugin(Object o) {
- //生成object对象的动态代理对象
- return Plugin.wrap(o, this);
- }
- //设置代理对象的参数
- @Override
- public void setProperties(Properties properties) {
- //如果项目中分页的pageSize是统一的,也可以在这里统一配置和获取,这样就不用每次请求都传递pageSize参数了。参数是在配置拦截器时配置的。
- String limit1 = properties.getProperty("limit", "10");
- this.pageSize = Integer.valueOf(limit1);
- this.dbType = properties.getProperty("dbType", "mysql");
- }
- }
②、全局配置文件增加plugin设置(注意位置)
- <!-- 配置自定义分页插件 -->
- <plugins>
- <plugin interceptor="com.thr.interceptor.MyPageInterceptor">
- </plugin>
- </plugins>
③、接口方法
- //分页查询所有用户,通过原生自定义拦截器
- List<User> selectAllUserByPage(Map map);
由于拦截器中设置了拦截以.ByPage结尾的方法,所以方法一定要命名正确,
④、sql映射
- <!-- 分页查询所有用户,通过自定义拦截器 -->
- <select id="selectAllUserByPage" resultMap="userMap">
- select * from t_user
- </select>
⑤、测试方法
5、PageHelper分页插件
PageHelper是一款非常优秀的分页插件,用的人非常多,详细的可以参考PageHelper的官方文档,讲的比较通俗易懂。链接:https://pagehelper.github.io/docs/howtouse/。 PageHelper分页其实也是自定义拦截器方式的一种第三方实现,它内部帮助我们实现了Interceptor的功能。所以实际上我们在执行查询方法之前,PageHelper分页插件同样是对我们的 sql 进行拦截,然后对分页参数进行拼接。
PageHelper的简单使用:
①、引入PageHelper依赖:
- <!-- pagehelper分页插件 -->
- <dependency>
- <groupId>com.github.pagehelper</groupId>
- <artifactId>pagehelper</artifactId>
- <version>5.2.0</version>
- </dependency>
②、全局配置文件增加plugin设置(注意位置)
- <!-- 配置分页插件 -->
- <plugins>
- <!-- PageHelper5版本配置 -->
- <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
- </plugins>
③、接口方法
- //分页查询所有用户,通过PageHelper
- List<User> selectAllUserByPageHelper();
④、sql映射
- <!-- 分页查询所有用户,通过PageHelper -->
- <select id="selectAllUserByPageHelper" resultMap="userMap">
- select * from t_user
- </select>
⑤、测试方法
- //分页查询所有用户信息,通过PageHelper
- @Test
- public void selectAllUserByPageHelper(){
- int currPage = 2;//当前页码
- int pageSize = 3;//当前页记录数量
- //表示获取第2页,3条内容,默认会查询总数count
- PageHelper.startPage(currPage,pageSize);
- List<User> userList = mapper.selectAllUserByPageHelper();
- for (User user : userList) {
- System.out.println(user);
- }
- }
⑥、运行结果
以上只是PageHelper的简单介绍,还有更多的功能可以去参考官方文档,也可以自行百度学习。
Mybatis3详解(十四)----Mybatis的分页的更多相关文章
- Linux学习之用户配置文件详解(十四)
Linux学习之用户配置文件详解 目录 用户信息文件/etc/password 影子文件/etc/shadow 组信息文件/etc/group 组密码文件/etc/gshadow 用户信息文件/etc ...
- Nginx详解十四:Nginx场景实践篇之代理服务
代理的作用 Nginx代理 正向代理 反向代理 正向代理和反向代理的区别:代理的对象不一样 正向代理代理的对象是客户端,反向代理代理的对象是服务端 反向代理: 配置语法:proxy_pass URL; ...
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...
- ViewPager 详解(四)----自主实现滑动指示条
前言:前面我们用了三篇的时间讲述了有关ViewPager的基础知识,到这篇就要进入点实际的了.在第三篇<ViewPager 详解(三)---PagerTabStrip与PagerTitleStr ...
- spring事务详解(四)测试验证
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- RocketMQ详解(四)核心设计原理
专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...
- OutputCache属性详解(四)— SqlDependency
目录 OutputCache概念学习 OutputCache属性详解(一) OutputCache属性详解(二) OutputCache属性详解(三) OutputCache属性详解(四)— SqlD ...
- IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构(转载)
IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构 系列文章链接: IIS负载均衡-Application Request Route详解第一篇: ...
- 前端技术之_CSS详解第四天
前端技术之_CSS详解第四天 一.第三天的小总结 盒模型box model,什么是盒子? 所有的标签都是盒子.无论是div.span.a都是盒子.图片.表单元素一律看做文本. 盒模型有哪些组成: wi ...
- Keepalived详解(四):通过vrrp_script实现对集群资源的监控【转】
一.通过vrrp_script实现对集群资源的监控: Keepalived基础HA功能时用到了vrrp_script这个模块,此模块专门用于对集群中服务资源进行监控.与此模块一起使用的还有track_ ...
随机推荐
- Day07_37_深度剖析集合中的contains()方法
深度剖析集合中的 contains()方法 contains()方法查找集合中是否包含某个元素 contains() 底层使用的是 equals()方法 当contains()方法拿到一个对象的时候, ...
- 什么是SQL注入漏洞?
什么是SQL注入: SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL. SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字 ...
- k8s 安装 rabbitMQ 单机版
rabbitMQ docker镜像使用rabbitmq:3.8-management service.yaml文件 apiVersion: v1 kind: Service metadata: nam ...
- 数据分析处理之PCA OLSR PCR PLSR(NIPALS)及其Matlab代码实现
传统的OLS(普通最小二乘)方法无法解决样本数据的共线性(multicollinearity)问题,如果你的数据样本中每个特征变量具有共线性,那么使用基于PCA的PCR和PLSR方法对数据样本进行回归 ...
- hdu1024 最大m子序列和
题意: 给你一个序列n个数组成,然后让你在里面找到m个子序列,让这m个子序列的和最大. 思路: dp[i][j]表示的是第j个数字在第i个子序列时的当前最优值. dp[i][j] ...
- hdu4930 模拟斗地主
题意: 模拟斗地主,出牌有一下规则,1张,1对,3张,3带1,3带2,炸弹(包括两个猫),4带2,这写规则,没有其他的,然后给你两幅牌,只要第一个人出了一次牌对方管不上,那么或者第一个人 ...
- 神经网络与机器学习 笔记—多层感知器(MLP)
多层感知器(MLP) Rosenblatt感知器和LMS算法,都是单层的并且是单个神经元构造的神经网络,他们的局限性是只能解决线性可分问题,例如Rosenblatt感知器一直没办法处理简单异或问题.然 ...
- xxl-job滥用netty导致的问题和解决方案
netty作为一种高性能的网络编程框架,在很多开源项目中大放异彩,十分亮眼,但是在有些项目中却被滥用,导致使用者使用起来非常的难受. 本篇文章将会讲解xxl-job作为一款分布式任务调度系统是如何滥用 ...
- HR:“最喜欢阿里出来的程序员了,技术又好又耐艹!” 我:???
面试造火箭,进厂拧螺丝?真的是这样吗? 缘起 估计不少同学都是被标题吸引进来的.事先声明,这句话不是我虚构的,而是我实实在在从同事的口中听到的,而且还不止一次. 当时的场景就是很正常的交谈,别人也并没 ...
- 将HTML字符串编译为虚拟DOM对象的基础实现
本文所有代码均保存在HouyunCheng / mini-2vdom 虚拟DOM只是实现MVVM的一种方案,或者说是视图更新的一种策略,是实现最小化更新的diff算法的操作对象. 创建扫描器 所有编译 ...