mybatis實現 主從表 left join 1:n 一對多 分頁查詢 主表從表都有查詢條件+count
需求:
========================================
1.主從表數據 是 1:m
2.主從表各自都有查詢條件
3.最后查詢結果 需要分頁,並統計總數
注意:
=======================================
1.查詢的分頁,必須在數據庫做,否則分頁沒有意義
解決方法:
注意 下面的入參中 [第一頁的10條]
pageNum=0
PageSize=10
實際入參應該是處理過的
pageNum = pageNum*10
pageSize = 10
##############################有對應實體接收查詢結果的情況下################################
1.mapper.xml應該這么寫
<resultMap type="com.lsrsjava.daywork.domain.week.自定義Bean" id="myResultMap"> <id column="id" property="id"/> <!--一堆的主表 屬性--> <result column="userId" property="userId"/> <result column="userName" property="userName"/> <result column="userImg" property="userImg"/> <!--子表對應的屬性 封裝在list中 即接收了 主表對子表的 1:N --> <collection property="listData" javaType="com.lsrsjava.daywork.domain.week.子表Bean" columnPrefix="slaveTable_"> <id column="id" property="id"/> <result column="rowId" property="rowId"/> <result column="colName" property="colName"/> <result column="val" property="val"/> </collection> </resultMap> <select id="pageFind" resultMap="myResultMap" parameterType="com.lqjava.daywork.api.beans.WorksheetDataSaveBean"> SELECT base.id, t.id slaveTable_id, t.row_id slaveTable_rowId, t.col_name slaveTable_colName, t.val slaveTable_val FROM ( SELECT * FROM worksheet_data_${dataId} WHERE -- 此處之后加 主表的 where查詢條件拼接 LIMIT #{pageNum}, #{pageSize} ) base LEFT JOIN worksheet_data_table_data t ON base.id = t.row_id WHERE <!-- 此處之后加 子表單的 where查詢拼接 --> </select>
2.mapper.java應該這么寫
List<自定義的Bean> pageFind(WorksheetDataSaveBean queryBean);
############################### 不確定返回字段類型[即表中屬性是動態的,沒有對應實體的情況下]###################################
1.mapper.xml中應該這么寫
[下面的示例中:因為我不確定返回的字段,所以用HashMap直接接收查詢結果后 自己處理的結果集]
<select id="pageFind" resultType="java.util.HashMap" parameterType="com.lsrjava.daywork.api.beans.WorksheetDataSaveBean"> SELECT base.*, t.id slaveTable_id, t.row_id slaveTable_rowId, t.col_name slaveTable_colName, t.val slaveTable_val FROM ( SELECT * FROM worksheet_data_${dataId}
WHERE -- 此處之后加 主表的 where查詢條件拼接 LIMIT #{pageNum}, #{pageSize} ) base LEFT JOIN worksheet_data_table_data t ON base.id = t.row_id
WHERE
<!-- 此處之后加 子表單的 where查詢拼接 --> </select>
2.mapper.java應該這么寫
List<Map<String,String>> pageFind(WorksheetDataSaveBean queryBean);
===================================count=============================================
count 是什么?count就是頁面的 總共total條數
1.mapper.xml應該這么寫
<select id="count" parameterType="com.lqjava.daywork.api.beans.WorksheetDataSaveBean" resultType="java.lang.Long"> SELECT count( DISTINCT base.id ) count FROM worksheet_data_${dataId} base LEFT JOIN worksheet_data_table_data c ON c.row_id = base.id -- 拼接條件的地方 </select>
2.mapper.java應該這么寫
Long count(WorksheetDataSaveBean queryBean);
====================================附錄,完整的 分頁+left join+count+不確認返回列+Map接收+mybatis標簽嵌套+json字段查詢+字符串轉日期+字符串轉數值+結果集封裝處理========================================
需求:
1.數據表 列是動態的多列,因此不確定查詢返回是哪些列【因此使用Map接收】
2.主表一行 關聯 子表的多行 【因此需要left join】
3.對於主表和子表的所有列,需要提供查詢功能【因此需要使用mybatis標簽拼接查詢條件】
4.主表是正常數據,子表是JSON數據存儲【因此需要提供有關JSON字段查詢處理的操作】
5.查詢出的List<Map>結果集 size=主size*子size 【因此,結果集需要將子表數據封裝進主表數據集 java處理】
6.上述結果集條數不能作為分頁查詢的count統計,返回總頁碼【因此需要額外count()查詢,以返回正確的total】
代碼參考:
1.Mapper.xml【一個page查詢 一個count查詢】

<select id="pageFind" resultType="java.util.HashMap" parameterType="com.lqjava.daywork.api.beans.WorksheetDataSaveBean"> SELECT base.*, u.name create_by_name, u2.name update_by_name, t.id slaveTable_id, t.row_id slaveTable_rowId, t.col_name slaveTable_colName, t.val slaveTable_val FROM ( SELECT d.* FROM worksheet_data_${dataId} d <!-- 此處之后加 主表的 where查詢條件拼接 --> <where> <if test="list != null"> <foreach collection="list" item="item" index="index" separator="AND" open="(" close=")"> <choose> <when test='item.cname.contains("date")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> DATE_FORMAT(${item.cname} , ${item.dateFormat} ) BETWEEN DATE_FORMAT( #{item.value}, ${item.dateFormat} ) AND DATE_FORMAT( #{item.endValue}, ${item.dateFormat} ) </when> <otherwise> DATE_FORMAT( ${item.cname}, ${item.dateFormat} ) = DATE_FORMAT( #{item.value}, ${item.dateFormat} ) </otherwise> </choose> </when> <when test='item.cname.contains("input-number")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> CAST(${item.cname} AS DECIMAL) BETWEEN #{item.value} AND #{item.endValue} </when> <otherwise> CAST(${item.cname} AS DECIMAL) = #{item.value} </otherwise> </choose> </when> <when test='item.cname.contains("checkbox") or item.cname.contains("select")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> FIND_IN_SET( #{v},${item.cname} ) </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> FIND_IN_SET( #{v},${item.cname} ) </foreach> </otherwise> </choose> </if> </when> <when test='item.cname.contains("dept-user") or item.cname.contains("dept-base")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> <choose> <when test='item.operator.contains("like") '> ${item.cname} -> '$[*].name' like '%${v}%' </when> <otherwise> JSON_CONTAINS( ${item.cname} ->'$[*].name' , '"${v}"', '$') </otherwise> </choose> </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> <choose> <when test='item.operator.contains("like") '> ${item.cname} -> '$[*].name' like '%${v}%' </when> <otherwise> JSON_CONTAINS( ${item.cname} ->'$[*].name' , '"${v}"', '$') </otherwise> </choose> </foreach> </otherwise> </choose> </if> </when> <otherwise> <choose> <when test='item.operator.contains("like") '> ${item.cname} like '%${item.value}%' </when> <otherwise> ${item.cname} = #{item.value} </otherwise> </choose> </otherwise> </choose> </foreach> </if> </where> LIMIT #{pageNum}, #{pageSize} ) base LEFT JOIN (SELECT * from worksheet_data_table_data where data_id = #{dataId}) t ON base.id = t.row_id LEFT JOIN dept_user u ON base.create_by = u.id LEFT JOIN dept_user u2 ON base.update_by = u2.id <!-- 此處之后加 子表單的 where查詢拼接 --> <where> <if test="slaveList != null"> <foreach collection="slaveList" item="item" index="index" separator="AND" open="(" close=")"> t.col_name = #{item.tableName} AND <choose> <when test='item.cname.contains("date")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> STR_TO_DATE(val -> '$.${item.cname}','"%Y-%m-%d %H:%i:%s"') between #{item.value} AND date_add(#{item.endValue}, interval 1 day) </when> <otherwise> STR_TO_DATE(val -> '$.${item.cname}','"%Y-%m-%d %H:%i:%s"') between #{item.value} AND date_add(#{item.value}, interval 1 day) </otherwise> </choose> </when> <when test='item.cname.contains("input-number")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> CAST(val -> '$."${item.cname}"' AS DECIMAL) BETWEEN #{item.value} AND #{item.endValue} </when> <otherwise> CAST(val -> '$."${item.cname}"' AS DECIMAL) = #{item.value} </otherwise> </choose> </when> <when test='item.cname.contains("checkbox") or item.cname.contains("select")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> val -> '$.${item.cname}' like '%,${v},%' </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> val -> '$.${item.cname}' like '%,${v},%' </foreach> </otherwise> </choose> </if> </when> <when test='item.cname.contains("dept-user") or item.cname.contains("dept-base")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> val -> '$."${item.cname}"' like '%${v}%' </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> val -> '$."${item.cname}"' like '%${v}%' </foreach> </otherwise> </choose> </if> </when> <otherwise> <choose> <when test='item.operator.contains("like") '> val -> '$.${item.cname}' like '%${item.value}%' </when> <otherwise> JSON_CONTAINS( val ->'$.${item.cname}' , '"${item.value}"', '$') </otherwise> </choose> </otherwise> </choose> </foreach> </if> </where> </select> <select id="count" parameterType="com.lqjava.daywork.api.beans.WorksheetDataSaveBean" resultType="java.lang.Long"> SELECT count( DISTINCT base.id ) count FROM worksheet_data_${dataId} base LEFT JOIN (SELECT * from worksheet_data_table_data where data_id = #{dataId}) c ON c.row_id = base.id <!-- 主表 + 子表 查詢條件拼接 --> <where> <if test="list != null"> <foreach collection="list" item="item" index="index" separator="AND" open="(" close=")"> <choose> <when test='item.cname.contains("date")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> DATE_FORMAT(${item.cname} , ${item.dateFormat} ) BETWEEN DATE_FORMAT( #{item.value}, ${item.dateFormat} ) AND DATE_FORMAT( #{item.endValue}, ${item.dateFormat} ) </when> <otherwise> DATE_FORMAT( ${item.cname}, ${item.dateFormat} ) = DATE_FORMAT( #{item.value}, ${item.dateFormat} ) </otherwise> </choose> </when> <when test='item.cname.contains("input-number")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> CAST(${item.cname} AS DECIMAL) BETWEEN #{item.value} AND #{item.endValue} </when> <otherwise> CAST(${item.cname} AS DECIMAL) = #{item.value} </otherwise> </choose> </when> <when test='item.cname.contains("checkbox") or item.cname.contains("select")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> FIND_IN_SET( #{v},${item.cname} ) </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> FIND_IN_SET( #{v},${item.cname} ) </foreach> </otherwise> </choose> </if> </when> <when test='item.cname.contains("dept-user") or item.cname.contains("dept-base")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> <choose> <when test='item.operator.contains("like") '> ${item.cname} -> '$[*].name' like '%${v}%' </when> <otherwise> JSON_CONTAINS( ${item.cname} ->'$[*].name' , '"${v}"', '$') </otherwise> </choose> </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> <choose> <when test='item.operator.contains("like") '> ${item.cname} -> '$[*].name' like '%${v}%' </when> <otherwise> JSON_CONTAINS( ${item.cname} ->'$[*].name' , '"${v}"', '$') </otherwise> </choose> </foreach> </otherwise> </choose> </if> </when> <otherwise> <choose> <when test='item.operator.contains("like") '> ${item.cname} like '%${item.value}%' </when> <otherwise> ${item.cname} = #{item.value} </otherwise> </choose> </otherwise> </choose> </foreach> </if> <if test="slaveList != null"> AND <foreach collection="slaveList" item="item" index="index" separator="AND" open="(" close=")"> c.col_name = #{item.tableName} AND <choose> <when test='item.cname.contains("date")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> STR_TO_DATE(val -> '$.${item.cname}','"%Y-%m-%d %H:%i:%s"') between #{item.value} AND date_add(#{item.endValue}, interval 1 day) </when> <otherwise> STR_TO_DATE(val -> '$.${item.cname}','"%Y-%m-%d %H:%i:%s"') between #{item.value} AND date_add(#{item.value}, interval 1 day) </otherwise> </choose> </when> <when test='item.cname.contains("input-number")'> <choose> <when test='item.operator.contains("between") and item.endValue != null'> CAST(val -> '$."${item.cname}"' AS DECIMAL) BETWEEN #{item.value} AND #{item.endValue} </when> <otherwise> CAST(val -> '$."${item.cname}"' AS DECIMAL) = #{item.value} </otherwise> </choose> </when> <when test='item.cname.contains("checkbox") or item.cname.contains("select")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> val -> '$.${item.cname}' like '%,${v},%' </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> val -> '$.${item.cname}' like '%,${v},%' </foreach> </otherwise> </choose> </if> </when> <when test='item.cname.contains("dept-user") or item.cname.contains("dept-base")'> <if test="item.valueList != null"> <choose> <when test=' "OR".equals(item.reOperator) '> <foreach collection="item.valueList " item="v" index="i" separator="OR" open="(" close=")"> val -> '$."${item.cname}"' like '%${v}%' </foreach> </when> <otherwise> <foreach collection="item.valueList " item="v" index="i" separator="AND" open="(" close=")"> val -> '$."${item.cname}"' like '%${v}%' </foreach> </otherwise> </choose> </if> </when> <otherwise> <choose> <when test='item.operator.contains("like") '> val -> '$.${item.cname}' like '%${item.value}%' </when> <otherwise> JSON_CONTAINS( val ->'$.${item.cname}' , '"${item.value}"', '$') </otherwise> </choose> </otherwise> </choose> </foreach> </if> </where> </select>
2.Mapper.java
List<Map<String,String>> pageFind(WorksheetDataSaveBean queryBean);
Long count(WorksheetDataSaveBean queryBean);
3.入參數據結構

public class WorksheetDataSaveBean { private Long dataId; private Long rowId; private List<WorksheetData> list; //入參集合 private List<WorksheetData> resultList;//結果列集合 要返回哪些列信息 private List<WorksheetData> slaveList;//子表單查詢條件 private Integer pageNum = 0; private Integer pageSize = 10;

public class WorksheetData { public static final Integer DATE_UNIT_SECOND = 1; public static final Integer DATE_UNIT_MINUTE = 2; public static final Integer DATE_UNIT_HOUR = 3; public static final Integer DATE_UNIT_DAY = 4; public static final Integer DATE_UNIT_MONTH = 5; public static final Integer DATE_UNIT_YEAR = 6; public static final String RELATED_OPERATOR_AND = "AND"; public static final String RELATED_OPERATOR_OR = "OR"; private Long id; private String cname; private String value; private String tableName;//子表單cname 對應的子表單列 在主表單中的列名 例如:table_0 table_1 private String operator = "equals";//操作符 [equals] / [between and] / [like] / private String reOperator = RELATED_OPERATOR_AND;//查詢條件[條件內] 關聯符 AND(默認) OR 提供給select/checkbox/dept-user/dept-base使用 private String endValue;//區間操作 結束區間值 提供給date/input-number 字段使用 private Integer dateUnit = DATE_UNIT_DAY;// 按秒、分、時、天(默認)、月、年 提供給date字段查詢使用 private String dateFormat; private List<String> valueList;//對checkbox、select 提供多值查詢功能 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public String getValue() { return value; } public void setValue(String value) { this.value = value; initValueList(); } public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } public String getEndValue() { return endValue; } public void setEndValue(String endValue) { this.endValue = endValue; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getReOperator() { return reOperator; } public void setReOperator(String reOperator) { this.reOperator = reOperator; } public Integer getDateUnit() { return dateUnit; } public void setDateUnit(Integer dateUnit) { this.dateUnit = dateUnit; initDateFormat(); } public String getDateFormat() { return dateFormat; } public void setDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public List<String> getValueList() { return valueList; } public void setValueList(List<String> valueList) { this.valueList = valueList; } private String initDateFormat(){ dateFormat = "'%Y-%m-%d %H:%i:%S'"; switch (dateUnit){ case 1:dateFormat = "'%Y-%m-%d %H:%i:%S'";break; case 2:dateFormat = "'%Y-%m-%d %H:%i'";break; case 3:dateFormat = "'%Y-%m-%d %H'";break; case 4:dateFormat = "'%Y-%m-%d'";break; case 5:dateFormat = "'%Y-%m'";break; case 6:dateFormat = "'%Y'";break; default:dateFormat = "'%Y-%m-%d'"; } return dateFormat; } private void initValueList(){ List<String> list = null; if (this.cname.contains("select") || this.cname.contains("checkbox") || this.cname.contains("dept-user") || this.cname.contains("dept-base")){ String[] split = this.value.split(","); list = Arrays.asList(split); } this.valueList = list; } }
4.controller

@RequestMapping(value = "/pageFindTableData",method = RequestMethod.POST,name="表單數據分頁全字段查詢") public PageResultBean<Map<String, Object>> pageFindTableData(@RequestBody WorksheetDataSaveBean bean){ PageResultBean<Map<String, Object>> res = new PageResultBean<>(); Long dataId = bean.getDataId(); int pageNum = bean.getPageNum(); int pageSize = bean.getPageSize(); pageNum = pageNum * pageSize; bean.setPageNum(pageNum); /** * 1.表名驗證 + 列名驗證 */ if (dataId != null){ String tableName = DDLCreater.TABLE_NAME+dataId; //表名驗證 String exist = mapper.checkTableExist(tableName); if(StringUtils.isNotBlank(exist)){ //列名驗證 boolean flag = true; List<WorksheetData> paramList = bean.getList(); if (paramList != null && paramList.size() > 0){ flag = checkColName(dataId,paramList,true); } /** * 2.區分主表子表查詢條件 + DB查詢 + 組裝結果集 */ if (flag){ //主子拆分 diffSlaveList(bean); //DB查詢 List<Map<String, String>> maps = tableDataMapper.pageFind(bean); //組裝結果 WorksheetPageFindMap map = new WorksheetPageFindMap(); List<Map<String, Object>> result = map.dealMap(maps); //返回 res.initTrue(result,tableDataMapper.count(bean)); }else { res.initFalse("列名不合法"); } }else { res.initFalse("數據表不存在"); } }else { res.initFalse("必填參數缺失"); } return res; }
檢查表是否存在的sql

<select id="checkTableExist" resultType="java.lang.String" parameterType="java.lang.String"> SELECT table_name FROM information_schema.TABLES WHERE table_name = #{tableName}; </select>
列名檢查 以及 區分主表和子表的查詢條件[因為主表是正常數據,子表是JSON數據,查詢方式不同,因此需要區分處理]

/** * 列名合法性檢查 * [並處理 列名 加上``符號] * * =======處理列名注意======= * 只有主表單字段 需要處理列名 * 子表單查詢字段 列名無需處理【json中查詢 字段不能帶 ``查詢】 * * * @param dataId dataId * @param paramList 入參列名集合 * @param includeSlaveTable 是否包含子表單列 * @return 列名是否合法 */ private boolean checkColName(Long dataId,List<WorksheetData> paramList,boolean includeSlaveTable){ int size = paramList.size(); WorksheetColBase check = new WorksheetColBase(); check.setDataid(dataId); check.setState(includeSlaveTable ? null: 0); List<WorksheetColBase> byDataIdCheckList = mapper.findByDataId(check); for (WorksheetData data : paramList) { String colName = data.getCname(); String tableName = data.getTableName(); for (WorksheetColBase worksheetColBase : byDataIdCheckList) { if (colName.equals(worksheetColBase.getColName())){ String tableColName = worksheetColBase.getTableColName(); if (tableName == null){ if (tableName == tableColName){ //處理列名 data.setCname("`"+colName+"`"); size--; } }else { if (tableName.equals(tableColName)){ size--; } } } } } return size == 0 ? true : false; } /** * 區分 子表單 查詢條件 和 主表查詢條件 * @param bean */ private void diffSlaveList(WorksheetDataSaveBean bean){ List<WorksheetData> list = bean.getList(); //入參查詢集合 if (list != null ){ List<WorksheetData> slaveList = new ArrayList<>(); //子表單查詢集合 for (int i = 0; i < list.size(); i++) { WorksheetData data = list.get(i); String tableName = data.getTableName(); if (tableName != null){ slaveList.add(data); list.remove(data); i--; } } bean.setSlaveList(slaveList); } }
組裝數據集的工具類

public class WorksheetPageFindMap { private Map<Long,Map<String,Object>> resultMap = new HashMap<>(); private Long rowId;//行ID private Map<String,Object> rowMap;//行Map private List<Map<String,String>> slaveList;//子表單List private Map<String,String> slaveMap;//子表單Map public List<Map<String, Object>> dealMap(List<Map<String,String>> list){ for (Map<String, String> oldMap : list) { rowMap = new HashMap<>(); slaveMap = new HashMap<>(); Set<String> keySet = oldMap.keySet(); for (String key : keySet) { String value = String.valueOf(oldMap.get(key)); if (key.equals("id")){ rowId = Long.valueOf(value); init(); append(key,rowId); }else { if (key.contains("slaveTable_")){ dealSlaveMap(key.split("slaveTable_")[1],value); }else { if (key.contains("date")){ value = value.split("\\.")[0]; } append(key,value); } } } dealSlaveList(); } List<Map<String, Object>> resultList = new ArrayList<>(); for (Map<String, Object> stringObjectMap : resultMap.values()) { resultList.add(stringObjectMap); } return resultList; } //初始化行方法 private void init(){ Map<String, Object> oldRowMap = resultMap.get(rowId); if (oldRowMap != null){ List<Map<String,String>> oldSlaveList = (List) oldRowMap.get("table"); if (oldSlaveList != null){ if (rowMap.get("table") == null){ slaveList = new ArrayList<>(); } slaveList.addAll(oldSlaveList); append("table",slaveList); } } resultMap.put(rowId,rowMap); } //行數據追加方法 private void append(String key,Object value){ rowMap.put(key,value); } //子表單集合 初始化 private void dealSlaveMap(String key,String value){ slaveMap.put(key,value); } //子表單List 處理 private void dealSlaveList(){ //說明有子表單數據 if (slaveMap.size() > 0 ){ slaveList = (List) rowMap.get("table"); if (slaveList == null){ slaveList = new ArrayList<>(); append("table",slaveList); } slaveList.add(slaveMap); } } }
最后conut ,拿到total,一起返回結果即可
返回結果集