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));
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM