zoukankan      html  css  js  c++  java
  • Mybatis中分页存在的坑1

    站在巨人的肩膀上

    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();
          }
      
      }
  • 相关阅读:
    CentOS8安装Mysql5.7
    CentOS8搭建FTP服务器
    CentOS8安装jdk1.8
    基于可穿戴设备的医疗监护系统
    air530GPS数据通过air202上传阿里云
    bzoj2594: [Wc2006]水管局长数据加强版
    bzoj3091: 城市旅行
    Problem A. Array Factory XVII Open Cup named after E.V. Pankratiev Stage 4: Grand Prix of SPb, Sunday, Octorber 9, 2016
    hdu5716
    bzoj2002: [Hnoi2010]Bounce 弹飞绵羊
  • 原文地址:https://www.cnblogs.com/longxok/p/10906085.html
Copyright © 2011-2022 走看看