项目地址:http://git.oschina.net/free/Mybatis_PageHelper

软件介绍:http://www.oschina.net/p/mybatis_pagehelper

分页插件演示样例: http://blog.csdn.net/isea533/article/details/24700339

v2.0更新内容:

  1. 支持Mybatis缓存。count和分页同一时候支持(二者同步)
  2. 改动拦截器签名。拦截Executor,签名例如以下:

    @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
  3. 将Page类移到外面,方便调用

有位朋友留言说插件不支持缓存。在使用缓存的情况下无法正常执行。

这个问题确实存在,由于缓存是CachingExecutor在v1.0版本号中的拦截器之前进行的,也就是说,当查询结果被缓存后。使用缓存的时候是进不到分页插件中的。并且分页插件无法取得返回的结果。因而不能正常执行,既然找到了原因,并且Executor也能够被拦截。我就在想是否能直接拦截Executor并且支持缓存。

通过查看源代码以及调试。找到一种可行的方法。而且经过多项測试到最后完毕,共计4小时。我測试的内容有缓存/不缓存两种情况,以及返回为resultType/resultMap两种情况,共计4种情况下的使用情况。

測试仍然不算全面,所以我希望使用该插件的各位朋友遇到问题能及时反馈。

这次更新和前一个版本号的实现方法毫无关联。并且也从来没人这么做过。所以有问题请及时反馈,以下说说详细的实现方法。

首先拦截器签名变了:

1 @Intercepts(@Signature(type
= Executor.
class,
2                        method
"query",
3                        args
= {MappedStatement.
class,
4                                Object.class,
5                                RowBounds.class,
6                                ResultHandler.class}))

查看完整代码请点击这里,以下讲一些实现的细节:

1 List<SqlNode>
contents = (List<SqlNode>) msObject.getValue(
"sqlSource.rootSqlNode.contents");

这段代码获取了SqlNode集合,Mybatis要运行的Sql从通过这个集合拼出来了,在第一个版本号的中的BoundSql就是通过contents中的内容生成的, 所以这样的分页方式绝对是意想不到的。获取这个对象后,做了例如以下处理:

1 //求count
- 重写sql
2 contents.add(0new TextSqlNode("select
count(0) from ("
));
3 contents.add(new TextSqlNode(")"));

往第一行插入了求count的sql,最后一行加了一个“)”,通过头尾加入的这两个,就让这一个正常的sql语句变成了一个求count的sql,以下这一句代码:

1 Class<?>
resultType = (Class<?

>) msObject.getValue("resultMaps[0].type");

这一句代码的作用是先把正常的返回值类型保存,然后做了例如以下改动:

1 msObject.setValue("resultMaps[0].type"int.class);

将返回值改为int类型。用于接收返回的count总数,另一句非常重要的代码:

1 List<ResultMapping>
resultMappings = (List<ResultMapping>) msObject.getValue(
"resultMaps[0].resultMappings");

这里也是先把resultMappings备份,这个值在使用resultMap的情况会对返回结果造成干扰。所以这里先备份,然后用一个空的list去取代:

1 msObject.setValue("resultMaps[0].resultMappings",
EMPTY_RESULTMAPPING);

然后就去运行这个改动后的sql:

01 //查询总数
02 Object
result = 
null;
03 try {
04     result
= invocation.proceed();
05     int totalCount
= Integer.parseInt(((List) result).get(
0).toString());
06     page.setTotal(totalCount);
07     int totalPage
= totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 
0)
0 1);
08     page.setPages(totalPage);
09 finally {
10     //清理count
sql
11     contents.remove(0);
12     contents.remove(contents.size()
1);
13     //恢复类型
14     msObject.setValue("resultMaps[0].type",
resultType);
15     msObject.setValue("resultMaps[0].resultMappings",
resultMappings);
16 }

由于这里运行了result = invocation.proceed()方法,所以在开启缓存的情况下,该sql也会被缓存,这里将结果totalCount保存到Page,然后在finally中运行了清理sql的方法和恢复类型的方法。这样就又变成了原来的sql。

这里通过运行过程中的截图来看一下实际效果:

添加头尾的count语句

运行的sql

后面使用同样的原理改动为分页SQL:

1 //分页sql
2 contents.add(0new TextSqlNode("select
* from ( select temp.*, rownum row_id from ( "
));
3 StringBuilder
pageSql = 
new StringBuilder(200);
4 pageSql.append("
) temp where rownum <= "
).append(page.getEndRow());
5 pageSql.append(")
where row_id > "
).append(page.getStartRow());
6 contents.add(new TextSqlNode(pageSql.toString()));

运行过程图:

添加头尾的分页sql

运行的sql

最后运行改动后的sql,保存处理结果:

01 //将运行权交给下一个拦截器
02 try {
03     result
= invocation.proceed();
04 finally {
05     //清理分页sql
06     contents.remove(0);
07     contents.remove(contents.size()
1);
08 }
09 //得到处理结果
10 page.setResult((List)
result);
11 //返回结果
12 return result;

这里仍然不能忘记在finally中清理sql。

通过这样的方法,全然使用了Mybatis的内容来操作,并且能够支持缓存。缓存对求count语句来说效果更明显,由于你查看下一页内容的时候不会反复运行count。会使用缓存。并且分页sql和count sql是同步缓存的。所以不用操心数据不一致的情况。并且这样的分页方式不影响原方法的单独运行(不分页)。

假设对你有帮助,或者有什么建议欢迎留言!

转载请注明原文地址和作者。

Mybatis分页插件2.0版本号公布的更多相关文章

  1. Mybatis分页插件

    mybatis配置 <!-- mybatis分页插件 --> <bean id="pagehelper" class="com.github.pageh ...

  2. Mybatis分页插件PageHelper的配置和使用方法

     Mybatis分页插件PageHelper的配置和使用方法 前言 在web开发过程中涉及到表格时,例如dataTable,就会产生分页的需求,通常我们将分页方式分为两种:前端分页和后端分页. 前端分 ...

  3. Mybatis分页插件PageHelper使用

    一. Mybatis分页插件PageHelper使用  1.不使用插件如何分页: 使用mybatis实现: 1)接口: List<Student> selectStudent(Map< ...

  4. SSM 使用 mybatis 分页插件 pagehepler 实现分页

    使用分页插件的原因,简化了sql代码的写法,实现较好的物理分页,比写一段完整的分页sql代码,也能减少了误差性. Mybatis分页插件 demo 项目地址:https://gitee.com/fre ...

  5. Mybatis学习---Mybatis分页插件 - PageHelper

    1. Mybatis分页插件 - PageHelper说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,S ...

  6. Mybatis分页插件PageHelper的实现

    Mybatis分页插件PageHelper的实现 前言 分页这个概念在做web网站的时候很多都会碰到 说它简单吧 其实也简单 小型的网站,完全可以自己写一个,首先查出数据库总条数,然后按照分页大小分为 ...

  7. 基于Mybatis分页插件PageHelper

    基于Mybatis分页插件PageHelper 1.分页插件使用 1.POM依赖 PageHelper的依赖如下.需要新的版本可以去maven上自行选择 <!-- PageHelper 插件分页 ...

  8. Mybatis分页插件-PageHelper的使用

    转载:http://blog.csdn.net/u012728960/article/details/50791343 Mybatis分页插件-PageHelper的使用 怎样配置mybatis这里就 ...

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

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

随机推荐

  1. java中与运算,或运算,异或运算,取反运算

      //与运算 &  规则 :都为1时才为1        System.out.println( 7 & 9);        /*         *  7二进制 0111     ...

  2. TensorFlow——分布式的TensorFlow运行环境

    当我们在大型的数据集上面进行深度学习的训练时,往往需要大量的运行资源,而且还要花费大量时间才能完成训练. 1.分布式TensorFlow的角色与原理 在分布式的TensorFlow中的角色分配如下: ...

  3. 给统计人讲Python(1)_科学计算库-Numpy

    本地代码是.ipynb格式的转换到博客上很麻烦,这里展示部分代码,了解更多可以查看我的git-hub:https://github.com/Yangami/Python-for-Statisticia ...

  4. quartz + spring 启动项目时,报错The web application [] appears to have started a thread named.........

    只是想记录自己的错误信息,下次再出现就知道怎么操作,不用再查找资料 解决办法: package com.wqq.quartz_test.schedule; import javax.servlet.S ...

  5. IDEA中Lombok插件的安装与使用

    背景   我们在开发过程中,通常都会定义大量的JavaBean,然后通过IDE去生成其属性的构造器.getter.setter.equals.hashcode.toString方法,当要对某个属性进行 ...

  6. Mac OS X10.9安装的Python2.7升级Python3.4步骤详解

    Mac OS X10.9安装的Python2.7升级Python3.4步骤详解 Mac OS X10.9默认带了Python2.7,不过现在Python3.4.0出来了,如果想使用最新版本,赶紧升级下 ...

  7. 带中横线的日期格式在iOS手机系统上 转换时间戳NaN问题

    类似于 '2019-04-01 14:13:00' 这样的日期格式转换时间戳在iOS手机上是无法转换的,需要先处理日期格式成 '2019/04/01 14:13:00' var str = '2019 ...

  8. Sql中Convert日期格式

    CONVERT(data_type,expression[,style]) convert(varchar(10),字段名,转换格式) 说明:此样式一般在时间类型(datetime,smalldate ...

  9. .NET中使用反射访问属性方法

    .net所编写的程序集包含两个重要部分:IL(中间语言代码) 和metadata(元数据).我们编写的代码中不是有很多很多的类吗,类有很多很多的成员,在编译代码的时候,元数据表就根据代码把类的所有信息 ...

  10. MongoDB: The Definitive Guide

    第一章 简介 MongoDB是面向文档的数据库,不是关系型数据库.内置对MapReduce的支持,以及对地理空间索引的支持. 丰富的数据模型 容易扩展,它所采用的面向文档的数据模型可以使其在多台服务器 ...