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();
          }
      
      }
  • 相关阅读:
    ASP.NET Web API 框架研究 Self Host模式下的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式下的消息处理管道
    ASP.NET Web API 框架研究 核心的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
    ASP.NET Web API 框架研究 ASP.NET Web API 路由
    ASP.NET Web API 框架研究 ASP.NET 路由
    ASP.NET Web API 入门 (API接口、寄宿方式、HttpClient调用)
    MVVM模式
    RESTful Web API 理解
    C# 函数式编程及Monads.net库
  • 原文地址:https://www.cnblogs.com/longxok/p/10906085.html
Copyright © 2011-2022 走看看