• mybatis分页与collection的冲突解决


    背景

    某个查询,是流水-发券类的查询,查询流水的同时,想要取得关联的卡券,关系是一对多的关系。希望返回给前端的结果如下:

    {
      "orderId":123,
      "num":1,
      "cardList": [
        {
    	   "id":0001,
    	   "cardCode":ASDAS15QWE,
    	}
      ]
    }
    

    问题点:

    1. 由于是订单流水,考虑数量比较大的情况,所以必须使用分页,且是使用服务器端的分页。
    2. 为了便于前端展示,最好使用[]的数组形式进行显示

    原本的处理(存在bug)

    数组的返回结果使用了resultMap的collection来进行处理,分页是mybatis-plus,其分页的本质是在sql 里加limit。
    本来数据少的时候没发现什么问题,造了点数据,数据多了就发现,单页存在card数组内容不全,重复等问题。
    比如假设数据:

    订单id 数量
    001 1
    002 2
    003 3
    004 4
    005 5
    卡券id 订单id 卡号
    1 001 c921dd66f922
    2 002 1991f9230af2
    3 002 bdf214812363
    4 003 f4b43652fc91
    5 004 d1663166f32c
    6 004 17a22b31fe7a
    7 004 0c9b35eda5e1

    如果订单分页限制是5条,正常的时候应该活全部取出,但是使用collection是,sql类似是如下:

    SELECT 订单id,数量,卡券id,卡号 FROM 订单 JOIN 卡券 ON 卡券.订单id = 订单.订单id
    

    以上sql 的result结果是8条,如果使用sql的limit,限制5条的话,后三条就无法取得。

    初版解决:

    卡券的select另写sql的mapper,使用单独查询,比如:

    <collection column="{条件}" select="另一sql"/>
    

    但是,这种情况,是mybatis在取得查询结果之后,对每条单独查询。比如一次查询取得5条件结果,则以上sql会执行5次。效率太低。

    最后解决(GROUP_CONCAT + 自定义typeHandler):

    首先,使用GROUP_CONCAT转换成String形式的json数据,如下:

    SELECT 订单id,
    	   数量,
    	   (SELECT CONCAT('[',IFNULL(GROUP_CONCAT(CONCAT('{ 卡券id:',卡券id,',卡号:',卡号,'}') Separator ','),''),']') FROM 卡券 WHERE 卡券.订单id = 订单.订单id) AS JSON
     FROM 订单 
    

    以上的sql的查询结果是[]形式的json数据。这样的数据其实返回给前端,让前端JSON.parse(返回数据)的方式进行处理也是可以的。但为了符合需求,使用mybatis自定义typeHandler的方法,给前端返回json的数据。
    相关代码如下:(json使用hutool)

    import cn.hutool.json.JSONArray;
    import cn.hutool.json.JSONException;
    import cn.hutool.json.JSONUtil;
    import cn.hutool.log.Log;
    import cn.hutool.log.LogFactory;
    import org.apache.ibatis.type.BaseTypeHandler;
    import org.apache.ibatis.type.JdbcType;
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class JsonArrayTypeHandler extends BaseTypeHandler {
        private static final Log log = LogFactory.get();
    
    
        // 核心的转换处理
        private JSONArray parse(String json) {
            try {
                if (json == null || json.length() == 0) {
                    return null;
                }
                return JSONUtil.parseArray(json);
            }catch (JSONException e){
                log.error(json);
                log.error(e);
                return null;
            }
        }
    
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
            ps.setString(i,parameter.toString());
        }
    
        @Override
        public JSONArray getNullableResult(ResultSet rs, String columnName) throws SQLException {
            return parse(rs.getString(columnName));
        }
    
        @Override
        public JSONArray getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            return parse(rs.getString(columnIndex));
        }
    
        @Override
        public JSONArray getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            return parse(cs.getString(columnIndex));
        }
    }
  • 相关阅读:
    ASP.NET Forums 2.0 修改集锦(一)
    在自己的应用程序中显示Windows关于对话框
    ASP.NET Forums 2.0 本地化修改(四)
    Flash对双字节的支持问题
    DotNetNuke 2.1.2安装指南
    ASP.NET Forums 2.0 本地化修改(五) 增加页面Meta标记的keywords和description
    ASP.NET Forums 2.0 本地化修改(三)
    JavaScript利用正则表达式自己写数字判断函数
    hash表基础知识(转载)
    求子数组的最大和
  • 原文地址:https://www.cnblogs.com/changfanchangle/p/12882944.html
Copyright © 2020-2023  润新知