站在巨人的肩膀上

https://www.cnblogs.com/esileme/p/7565184.html

环境:Spring 4.2.1 Mybatis 3.2.8 pagehelper 5.1.2

Mybatis官方教程:https://github.com/pagehelper/Mybatis-PageHelper/blob/d5947437cc6272cb3f1b186cadee74f1f8072cbb/wikis/zh/HowToUse.md

  • 加入pageHelper依赖

     <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.2</version>
    </dependency>
  • 在Mybatis-config.xml中配置pageHelper的拦截器

     <plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
    <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
    <property name="helperDialect" value="mysql" />
    <property name="reasonable" value="true" />
    <property name="supportMethodsArguments" value="true" />
    <property name="autoRuntimeDialect" value="true" /> </plugin> </plugins>
  • 调用startPage()分页方法,在获取数据后将数据放到PageInfo对象中。

     PageHelper.startPage(page, pageSize);
    List<Map<String, Object>> list = itemMapper.getItems();
    PageInfo<Map<String, Object>> pageInfor = new PageInfo<Map<String, Object>>(list);

即可对数据进行分页处理。

Mybatis使用pageHelper分页出现的问题

在pageHelper的文档中,我们可以看到这样的提示分页插件不支持嵌套结果映射https://github.com/pagehelper/Mybatis-PageHelper/blob/d5947437cc6272cb3f1b186cadee74f1f8072cbb/wikis/zh/Important.md),由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。这时候对于一些嵌套查询来说使用通用pageHelper已经不能用了,因此需要我们通过手动分别查询分页数据以及分页数据的映射数据。

通过使用一个例子对pageHelper进行测试不兼容嵌套查询的结果映射:

 <resultMap type="java.util.Map" id="fatherMap">
<result column="orderId" property="orderId" />
<result column="payment" property="payment" />
<result column="buyer_nick" property="buyerNick" />
<result column="shipping_code" property="shippingCode" />
<result column="state" property="state" />
</resultMap> <resultMap type="java.util.Map" id="orderMap" extends="fatherMap"> <collection property="items" javaType="ArrayList" resultMap="itemMap" /> </resultMap> <select id="getOrdersByUserId" resultMap="orderMap"> SELECT o.order_id AS orderId,o.payment ,o.buyer_nick,o.shipping_code
,o.status AS orderState,i.title ,i.price FROM tb_order AS o,tb_item AS
i,tb_order_item AS oi WHERE o.user_id=#{userId} AND
oi.order_id=o.order_id AND i.id=oi.item_id </select>
   /*Service层代码*/
public List<Map<String, Object>> getOrdersByUserId(String userId) { PageHelper.startPage(1, 2);
List<Map<String, Object>> list = orderMapper.getOrdersByUserId(userId);
return list; }

通过嵌套查询返回一个Map对象并嵌套了另一个表中的多条数据(List集合),在取出数据后,可以看到这样的结果:

可以发现,pageHelper对我们的子数据进行了分页,我们要两条数据且只是出现了一条数据,这个时候,就只有通过分别查询来取出数据了。

首先,对订单数据不进行关联查询,先把数据取出来,然后根据取出来的订单对象,再把关联的信息查出来,这样就可以使用pageHelper来进行操作了。在Service层的代码如下:

    public List<Map<String, Object>> getAnotherOrdersByUserId(String userId) {
PageHelper.startPage(1, 2);
List<Map<String, Object>> orderMaps = orderMapper.getAnotherOrdersByUserId(userId);
for (Map<String, Object> map : orderMaps) {
String orderId = (String) map.get("orderId");
List<Map<String, Object>> items = orderMapper.getItems(orderId);
map.put("items", items);
}
PageInfo pageInfor = new PageInfo(orderMaps);
System.out.println(pageInfor.getPageNum());
System.out.println(pageInfor.getTotal()); return orderMaps;
}

mapper的代码:

<select id="getAnotherOrdersByUserId" resultMap="fatherMap">

    SELECT o.order_id AS orderId,o.payment ,o.buyer_nick,o.shipping_code
,o.status AS orderState FROM tb_order AS o WHERE o.user_id=#{userId} </select> <select id="getItems" resultMap="itemMap"> SELECT item.title ,item.price FROM tb_order_item AS oi ,tb_item AS item
WHERE oi.order_id=#{orderId} AND oi.item_id=item.id </select>

这样通过分别查询就可以避免了pageHelper的联合查询的问题。

正确的数据显示:

Demo:https://github.com/esileme/MybatisPager

PageHelper分页原理

在Mybatis中,提供了一个Interceptor接口,Mybatis的PageInterceptor类实现了Interceptor接口,在这个接口中,MyBatis允许我们拦截四个方法(ParameterHandler、ResultSetHandler、StatementHandler、Executor),可以对这四个方法进行拦截并实现相应的操作。

我们可以自定义实现Interceptor方式对Mybatis返回为Map的对象进行数据库数据与pojo对象映射的操作:

  • 在Mybatis-config.xml中配置

    <plugin interceptor="com.yl.page.intercpter.CameHumpIntercpter"></plugin>
    code
  • package com.yl.page.intercpter;
    
    import java.sql.Statement;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set; import org.apache.ibatis.executor.resultset.ResultSetHandler;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.plugin.Intercepts;
    import org.apache.ibatis.plugin.Invocation;
    import org.apache.ibatis.plugin.Plugin;
    import org.apache.ibatis.plugin.Signature; @Intercepts( @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }))
    public class CameHumpIntercpter implements Interceptor { public Object intercept(Invocation invocation) throws Throwable {
    List<Object> values = (List<Object>) invocation.proceed();
    for (Object object : values) { if (object instanceof Map) {
    processMap((Map) object); } else {
    break;
    }
    }
    return values;
    } public Object plugin(Object target) { return Plugin.wrap(target, this);
    } // 获取配置参数
    public void setProperties(Properties properties) { } private void processMap(Map<String, Object> map) {
    Set<String> keySet = new HashSet<String>(map.keySet());
    for (String key : keySet) { if ((key.charAt(0) >= 'A' && key.charAt(0) <= 'Z') || key.indexOf("_") >= 0) { Object value = map.get(key);
    map.remove(key);
    map.put(undelineToNomall(key), value);
    }
    } } public String undelineToNomall(String inputString) {
    StringBuilder buder = new StringBuilder();
    boolean nextUpperCase = false;
    for (int i = 0; i < inputString.length(); i++) { char c = inputString.charAt(i);
    if (c == '_') {
    if (buder.length() > 0) {
    nextUpperCase = true;
    } } else { if (nextUpperCase) {
    buder.append(Character.toUpperCase(c)); nextUpperCase = false;
    } else {
    buder.append(Character.toLowerCase(c));
    } } } return buder.toString();
    } }

Mybatis中分页存在的坑1的更多相关文章

  1. mybatis中集成sharing-jdbc采坑

    1. mybatis中集成sharing-jdbc采坑 1.1. 错误信息 Caused by: org.apache.ibatis.binding.BindingException: Invalid ...

  2. mybatis中分页查询

    1 如果在查询方法中有多个参数,可以使用map对象将所有数据都存储进去.比如分页查询,需要用到两个参数,可以将这两个参数包装到map中. 例子:分页查询 dao层方法 public List<S ...

  3. mybatis中分页插件PageHelper的使用

    转载博客:http://blog.csdn.net/u012728960/article/details/50791343

  4. MyBatis中log4j 和 参数 和 分页和别名 功能

    1.配置全局文件,注意各个配置标签的顺序 properties?, settings?, typeAliases?, typeHandlers?, objectFactory?,   objectWr ...

  5. Oracle使用MyBatis中RowBounds实现分页查询

    Oracle中分页查询因为存在伪列rownum,sql语句写起来较为复杂,现在介绍一种通过使用MyBatis中的RowBounds进行分页查询,非常方便. 使用MyBatis中的RowBounds进行 ...

  6. Mybatis中使用PageHelper插件进行分页

    分页的场景比较常见,下面主要介绍一下使用PageHelper插件进行分页操作: 一.概述: PageHelper支持对mybatis进行分页操作,项目在github地址: https://github ...

  7. mybatis中的分页插件

    1.Mybatis的分页plugin实现原理 2.具体步骤 第一步.导入到pom.xml文件中依赖包 第二步.配置插件(必需) 在mybatisConfig.xml文件中配置以下代码 代码位置:在en ...

  8. mybatis中Oracle分页语句的写法

    最近一段时间使用oracle数据库查询分页, 用的是springboot. Oracle数据库中没有像mysql中limit的写法, 只能换其他方式写. 考虑到oracle中的ROWNUM变量, 使用 ...

  9. 记自己在mybatis中设置jdbcType的一个坑

    项目是用ssm搭建的.主要是为app数据接口.其中有一个需求就app想要查询一段时间内某个用户的测量信息,所以app给我后端传递了3个参数,分别是appuserId(String),startDate ...

随机推荐

  1. ajax json html 结合

    <table id="datas" border="1" cellspacing="0" style="border-col ...

  2. React-Router4按需加载

    其实几种实现都是近似的,但具体上不太一样,其中有些不需要用到bundle-loader 第一种:ReactTraining/react-router 介绍的基于 webpack, babel-plug ...

  3. linux定期判断网站可否打开

      wget http://www.shopindream.de/200.php --timeout=2 c_monitor=$? rm -rf 200.php if [ ! $c_monitor = ...

  4. SQL 系统表应用

    查看link server select DD.System,DD.DB,DD.previous_processing_dte, DD.processing_dte,LS.LinkServerName ...

  5. gradle中的 settings.gradle

    gradle 默认只执行当前目录下的build.gradle 脚本,而我们的项目通常是有多个模块依赖的,这时需要我们对多个目录同时编译,那就需要我们创建一个settings.gradle  文件 如果 ...

  6. Linux下Redis C++操作的封装

    安装和启动Redis服务...略!很粗糙的版本,待改进... Redis Client C++示例代码...略! /** * Time: 14-3-10 * File: RedisCache.h * ...

  7. Redis穿透问题解决方案

    缓存穿透 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有.这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空.这样请求就绕过缓存直接查数据库,这也是经常提的 ...

  8. MySQL索引优化-from 高性能MYSQL

    Btree: 1. 尽量使用覆盖索引, 即三星索引 2. 多列索引如果带范围的话, 后续列不会作为筛选条件 3. 多列索引应选择过滤性更好的充当前缀索引 4. 尽量按主键顺序插入, 减少页分裂, 采用 ...

  9. jmeter中的响应断言

    断言就类似LoadRunner中的检查点.对上一个请求返回的信息,做字符串.数据包大小.HTML.XML.图片等做判断,确保返回的信息的准确性. jmeter的断言有好多,下面是一个响应断言 新建一个 ...

  10. 【转载】String和StringBuffer的区别,以及StringBuffer的常用方法介绍

    String与StringBuffer的区别简单地说,就是一个变量和常量的关系.StringBuffer对象的内容可以修改:而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象.Stri ...