首页 > 其他分享 >Mybatis分页插件2.0版本发布

Mybatis分页插件2.0版本发布

时间:2023-01-02 19:00:23浏览次数:37  
标签:count 插件 缓存 分页 sql Mybatis 2.0 class contents


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并且支持缓存。

所以我希望使用该插件的各位朋友遇到问题能及时反馈。


从来没人这么做过,所以有问题请及时反馈,下面说说具体的实现方法。

    首先拦截器签名变了:


  @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中的内容生成的,  所以这种分页方式绝对是意想不到的 ,获取这个对象后,做了如下处理:

//求count - 重写sql
2
contents.add(0, new 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。

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

Mybatis分页插件2.0版本发布_mybatis

增加头尾的count语句

Mybatis分页插件2.0版本发布_插件_02

执行的sql

    后面使用相同的原理修改为分页SQL:


1
//分页sql
2
contents.add(0, new 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()));

    执行过程图:

Mybatis分页插件2.0版本发布_Mybatis物理分页_03

增加头尾的分页sql

Mybatis分页插件2.0版本发布_Mybatis物理分页_04

执行的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是同步缓存的,所以不用担心数据不一致的情况。而且这种分页方式不影响原方法的单独执行(不分页)。

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


标签:count,插件,缓存,分页,sql,Mybatis,2.0,class,contents
From: https://blog.51cto.com/isea533/5983961

相关文章

  • MyBatis中多对一和一对多数据的处理
    多对一的处理多对一的理解:多个学生对应一个老师如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师!1、数据库设计  CREATETABLE`teacher`(......
  • 05编写全球化的插件
    在上一章我们使用Pinia实现了全球化。但是在一个应用中不可能只有一个组件,我们需要在每个组件添加重复的计算属性代码,这样很麻烦。而Vue为我们提供了全局扩展属性,这样我们......
  • MyBatis配置解析
    核心配置文件mybatis-config.xml系统核心配置文件MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息。能配置的内容如下:configuration(配置)pr......
  • Mybatis的简介及测试
    1、Mybatis简介1.1、什么是MyBatisMyBatis是一款优秀的持久层框架MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的过程MyBatis可以使用简单......
  • idea翻译插件traslation链接google翻译引擎无效的办法
    原因:谷歌9月28日关闭了.cn的翻译服务器。10月22日,谷歌翻译API的内地服务器也关闭,现在 Chrome浏览器以及扩展均已无法使用翻译。 解决方案:修改hosts本地域名配置......
  • spring boot——spring boot的基本配置——spring boot整合mybatis——本地实例运行
    总体步骤按照如下:                第二步——修改pom文件:<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.ap......
  • spring boot——spring boot的基本配置——spring boot整合mybatis——教程
                  第二步——修改pom.xml文件:    pom文件:<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://mave......
  • Solon Java Framework v1.12.0 发布
    一个更现代感的Java应用开发框架:更快、更小、更自由。没有Spring,没有Servlet,没有JavaEE;独立的轻量生态。主框架仅0.1MB。@ControllerpublicclassApp{publ......
  • OpenFace 2.2.0安装步骤
    本文是安装OpenFace2.2.0的过程,以及安装时可能遇见的一系列问题。下载源码以及脚本对应的文件下载源码压缩包解压后,执行文件夹中的脚本download_libraries.ps1。该......
  • 号外!!!TypeScrip 2.0 版本 发布了
    TypeScript是一种基于JavaScript衍生的语言,是由微软为了使大型Web应用开发更容易而创造的一种语言,现在已经发布了2.0里程碑版本。在用于大型开发时,JavaScri......