目录

  • 前言
  • MyBatis插件
  • 手写分页插件
  • 总结

前言

在开发查询类的接口时,有一个让开发者比较头疼的问题:分页。
如果每次都要开发者自己去写limit,计算起始行和偏移量就太烦了,于是市面上诞生了一些优秀的分页插件,例如:PageHelper。

PageHelper使用起来非常简单,如下示例代码:

Page page = PageHelper.startPage(1, 10);
//sql: select * from table
mapper.selectList();

调用PageHelper.startPage(1, 10)方法后,在执行SQL时会自动加上limit分页,如下:

select * from table limit 0,10;

查看源码会发现PageHelper.startPage(1, 10)只做了一件事:构建Page实例存放到本地线程中。
它能修改执行的SQL语句得益于PageInterceptor类,基于Mybatis提供的Interceptor插件来实现的。

本篇博客并不想分析PageHelper的源码,感兴趣的同学可以自己去研究一下。

MyBatis插件

不管是PageHelper还是其他分页插件,实现的思路都是一样的,给予MyBatis提供的Interceptor插件机制,允许开发者在映射语句执行过程中进行方法的拦截,可以动态修改入参、SQL语句、返回结果等。

MyBatis允许被拦截的方法包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

详情请看官方文档:https://mybatis.org/mybatis-3/zh/configuration.html#plugins

手写分页插件

借鉴PageHelper的思路,自己手写一个分页插件,其实并不难。

Page类存放当前页和大小

//省略getter setter
public class Page {private Integer page;private Integer size;
}

PageUtil通过ThreadLocal传递Page实例

public class PageUtil {// Page通过ThreadLocal传递static final ThreadLocal<Page> THREAD_LOCAL_PAGE = new ThreadLocal<>();public static Page startPage(Integer page, Integer size) {Page pageResult = new Page();pageResult.setPage(page);pageResult.setSize(size);THREAD_LOCAL_PAGE.set(pageResult);return pageResult;}public static Page localPage() {return THREAD_LOCAL_PAGE.get();}public static void remove() {THREAD_LOCAL_PAGE.remove();}
}

PagePlugin,基于Interceptor实现的分页逻辑

// 拦截StatementHandler类的prepare方法
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class})})
public class PagePlugin implements Interceptor {private Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {Page page = PageUtil.localPage();//没有调用PageUtil.startPage(),则不分页if (page == null) {return invocation.proceed();}//取出原sql,根据page拼接分页sqlRoutingStatementHandler target = (RoutingStatementHandler) invocation.getTarget();BoundSql boundSql = target.getBoundSql();String sql = boundSql.getSql();int limit = (page.getPage() - 1) * page.getSize();ReflectUtil.setFieldValue(boundSql, "sql", sql + " limit " + limit + "," + page.getSize());//删除当前线程的page实例PageUtil.remove();//执行目标方法return invocation.proceed();}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}

配置插件

<plugins><plugin interceptor="com.ch.plugins.PagePlugin"></plugin>
</plugins>

Mapper接口

public interface UserMapper {@Select("select * from user")List<User> list();
}

分页测试类

public class PageTest {public static void main(String[] args) throws Exception {String resource = "mybatis.xml";InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);Configuration configuration = sqlSessionFactory.getConfiguration();SqlSession session = sqlSessionFactory.openSession();UserMapper mapper = session.getMapper(UserMapper.class);// 第1页,每页10条Page page = PageUtil.startPage(1, 10);for (User user : mapper.list()) {System.out.println(user);}session.close();} finally {IoUtil.close(inputStream);}}
}

执行后,控制台输出日志

DEBUG [main] - ==>  Preparing: select * from user limit 0,10
DEBUG [main] - ==> Parameters:
DEBUG [main] - <==      Total: 10

分页成功!

总结

主要记的是思路,分页插件写的比较简陋,只是简单的拼接SQL,也没有考虑到limit分页失效的问题。
感兴趣的同学可以基于这个思路继续优化!!!

手写MyBatis分页插件相关推荐

  1. Mybatis:Mybatis分页插件

    文章目录 1. Mybatis分页插件 1.1 分页插件介绍 1.2 分页插件的使用 1.3 分页插件的参数获取 1.4 分页插件知识小结 分页助手相关 API 1. Mybatis分页插件 1.1 ...

  2. 使用abel533大神的mybatis分页插件总结

    今天使用了abel533大神的mybatis分页插件,遇到了写问题,特意在这里做个总结,方便以后查找. 首先该测试是在本人的ssm基础框架上实现的,有兴趣的可以先看看本人的博客置顶帖.高手就略过吧. ...

  3. druid连接池初始化慢_从零开始手写 mybatis (三)jdbc pool 从零实现数据库连接池

    前景回顾 第一节 从零开始手写 mybatis(一)MVP 版本 中我们实现了一个最基本的可以运行的 mybatis. 第二节 从零开始手写 mybatis(二)mybatis interceptor ...

  4. (转)淘淘商城系列——MyBatis分页插件(PageHelper)的使用以及商品列表展示

    http://blog.csdn.net/yerenyuan_pku/article/details/72774381 上文我们实现了展示后台页面的功能,而本文我们实现的主要功能是展示商品列表,大家要 ...

  5. 都这么卷了,不懂MyBatis插件开发怎么行,教你实现一个MyBatis分页插件

    MyBatis可谓是Java开发工程师必须要掌握的持久层框架,它能够让我们更容易的通过Java代码操作数据库,并且它还有很高的扩展性,我们可以自定义插件,去让MyBatis的功能变的更为强大,本篇文章 ...

  6. 2. mybatis分页插件使用

    1.概述 在做系统的过程中,分页查询是我们经常遇到的一个场景,我们可以借助mybatis分页插件方便的实现分页功能,本文分享怎样使用mybatis分页插件. 2.mybatis分页插件使用 mybat ...

  7. MyBatis 分页插件

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 1.分页插件使用步骤 2.分页插件的使用 总结 前言 mybatis学习记录 12. MyBatis 分页插件 提示: ...

  8. 手写mybatis彻底搞懂框架原理

    mybatis的前身是iBatis,其源于"Internet"和"abatis"的组合,是一款优秀的持久层框架,它支持定制化SQL.存储过程以及高级映射.myb ...

  9. springboot整合mybatis分页插件

    1.springboot版本为2.0.1,数据库为mysql,引入pagehelper的pom依赖 <!--mybatis分页插件--> <dependency><gro ...

最新文章

  1. 放大器非线性失真研究装置设计报告_我校信息学院学子再次斩获大学生电子设计竞赛大奖...
  2. boost::serialization模块实现快速二进制归档的测试程序
  3. vue中mode的设置
  4. java显示目录文件列表和删除目录
  5. 常见字符编码 java
  6. MyBatis Criteria使用 OffsetLimitInterceptor.java分页报错
  7. 常用的正则表达式-收藏版
  8. 读取excel内容在网页上显示出来
  9. 开课吧Java课堂:如何使用迭代函数
  10. mysql服务的注册,启动、停止、注销。 [delphi代码实现]
  11. Git的学习笔记(一)
  12. Python深度学习:Python数据处理及可视化(读书笔记)
  13. 《SQL 入门经典》读书笔记(1)
  14. java代码生成UUID以及在线UUID生成器
  15. access建立er图_关于ER图的快速生成 | 学步园
  16. SSD性能怎么测?看这一篇就够了!
  17. PHP生成二维码与识别二维码,jq生成二维码
  18. python-jieba库
  19. vue 引入液晶数字字体
  20. 极域电子教室功能讲解-电子教室

热门文章

  1. 兰空图床(lsky-pro)V2.1的自动删除全部图片
  2. Pytorch基础知识(15)基于PyTorch的多标签图像分类
  3. 6/4 金汇金融杭州分公司面试
  4. 记一次ubuntu系统崩溃的修复
  5. Pytorch中backward函数
  6. Java如何制作带表格的word文档
  7. surfacecontrol.java_简单说说JAVA层中Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系...
  8. 11 的新增的String的处理方法
  9. 计算机怎么加网关命令,默认网关怎么设置,教您默认网关怎么设置
  10. 地下城勇士 DNF 资源分析