Skip to content

Commit 2f5d947

Browse files
committed
解决 SQL JOIN 在一对多或多对多时返回单独查询的重复副表数据,而不是 SQL 结果集里的副表数据
1 parent 5b2c1ed commit 2f5d947

File tree

6 files changed

+91
-37
lines changed

6 files changed

+91
-37
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java

+37-11
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ public AbstractObjectParser setParentPath(String parentPath) {
123123
return this;
124124
}
125125

126+
protected JSONObject cache;
127+
@Override
128+
public JSONObject getCache() {
129+
return cache;
130+
}
131+
132+
@Override
133+
public AbstractObjectParser<T> setCache(JSONObject cache) {
134+
this.cache = cache;
135+
return this;
136+
}
137+
126138
protected int position;
127139
public int getPosition() {
128140
return position;
@@ -243,6 +255,7 @@ public AbstractObjectParser parse(String name, boolean isReuse) throws Exception
243255

244256
int index = 0;
245257
// hasOtherKeyNotFun = false;
258+
JSONObject viceItem = null;
246259

247260
for (Entry<String, Object> entry : set) {
248261
if (isBreakParse()) {
@@ -280,7 +293,14 @@ else if (value instanceof JSONObject) { // JSONObject,往下一级提取
280293
childMap.put(key, (JSONObject)value);
281294
}
282295
else { // 直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
283-
response.put(key, onChildParse(index, key, (JSONObject)value));
296+
JSON cache = index <= 0 || type != TYPE_ITEM || viceItem == null ? null : viceItem.getJSONObject(key);
297+
JSON result = onChildParse(index, key, (JSONObject) value, cache);
298+
if (index <= 0 && type == TYPE_ITEM) {
299+
JSONObject mainItem = (JSONObject) result;
300+
viceItem = result == null ? null : (JSONObject) mainItem.remove(AbstractSQLExecutor.KEY_VICE_ITEM);
301+
}
302+
303+
response.put(key, result);
284304
index ++;
285305
}
286306
}
@@ -368,7 +388,7 @@ public boolean onParse(@NotNull String key, @NotNull Object value) throws Except
368388
+ JSONRequest.SUBQUERY_RANGE_ALL + ", " + JSONRequest.SUBQUERY_RANGE_ANY + "] 中的一个!");
369389
}
370390

371-
JSONArray arr = parser.onArrayParse(subquery, path, key, true);
391+
JSONArray arr = parser.onArrayParse(subquery, path, key, true, null);
372392

373393
JSONObject obj = arr == null || arr.isEmpty() ? null : arr.getJSONObject(0);
374394
if (obj == null) {
@@ -530,18 +550,19 @@ else if (isTable && key.startsWith("@") && JSONRequest.TABLE_KEY_LIST.contains(k
530550
* @param index
531551
* @param key
532552
* @param value
553+
* @param cache
533554
* @return
534555
* @throws Exception
535556
*/
536557
@Override
537-
public JSON onChildParse(int index, String key, JSONObject value) throws Exception {
558+
public JSON onChildParse(int index, String key, JSONObject value, JSON cache) throws Exception {
538559
boolean isFirst = index <= 0;
539560
boolean isMain = isFirst && type == TYPE_ITEM;
540561

541562
JSON child;
542563
boolean isEmpty;
543564

544-
if (apijson.JSONObject.isArrayKey(key)) {//APIJSON Array
565+
if (apijson.JSONObject.isArrayKey(key)) { // APIJSON Array
545566
if (isMain) {
546567
throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!"
547568
+ "数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} !不能为 arrayKey[]:{} !");
@@ -557,7 +578,7 @@ public JSON onChildParse(int index, String key, JSONObject value) throws Excepti
557578
}
558579

559580
String query = value.getString(KEY_QUERY);
560-
child = parser.onArrayParse(value, path, key, isSubquery);
581+
child = parser.onArrayParse(value, path, key, isSubquery, cache instanceof JSONArray ? (JSONArray) cache : null);
561582
isEmpty = child == null || ((JSONArray) child).isEmpty();
562583

563584
if ("2".equals(query) || "ALL".equals(query)) { // 不判断 isEmpty,因为分页数据可能只是某页没有
@@ -594,7 +615,8 @@ public JSON onChildParse(int index, String key, JSONObject value) throws Excepti
594615
}
595616
}
596617

597-
child = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null, isSubquery);
618+
child = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null
619+
, isSubquery, cache instanceof JSONObject ? (JSONObject) cache : null);
598620

599621
isEmpty = child == null || ((JSONObject) child).isEmpty();
600622
if (isFirst && isEmpty) {
@@ -776,7 +798,7 @@ public void onTableArrayParse(String key, JSONArray valueArray) throws Exception
776798
req = parser.parseCorrectRequest(method, childKey, version, "", req, maxUpdateCount, parser);
777799
}
778800
//parser.getMaxSQLCount() ? 可能恶意调用接口,把数据库拖死
779-
result = (JSONObject) onChildParse(0, "" + i, req);
801+
result = (JSONObject) onChildParse(0, "" + i, req, null);
780802
}
781803
catch (Exception e) {
782804
if (allowPartialFailed == false) {
@@ -1080,7 +1102,7 @@ public void onChildResponse() throws Exception {
10801102
if (set != null) {
10811103
int index = 0;
10821104
for (Entry<String, JSONObject> entry : set) {
1083-
Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue());
1105+
Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue(), null);
10841106
if (child == null
10851107
|| (child instanceof JSONObject && ((JSONObject) child).isEmpty())
10861108
|| (child instanceof JSONArray && ((JSONArray) child).isEmpty())
@@ -1106,8 +1128,11 @@ public Object onReferenceParse(@NotNull String path) {
11061128
public JSONObject onSQLExecute() throws Exception {
11071129
int position = getPosition();
11081130

1109-
JSONObject result;
1110-
if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓存数据
1131+
JSONObject result = getCache();
1132+
if (result != null) {
1133+
parser.putQueryResult(path, result);
1134+
}
1135+
else if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓存数据
11111136
result = parser.getArrayMainCacheItem(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2), position);
11121137
}
11131138
else {
@@ -1134,7 +1159,8 @@ public JSONObject onSQLExecute() throws Exception {
11341159
JSONObject obj = rawList.get(i);
11351160

11361161
if (obj != null) {
1137-
parser.putQueryResult(arrayPath + "/" + i + "/" + name, obj); // 解决获取关联数据时requestObject里不存在需要的关联数据
1162+
// obj.remove(AbstractSQLExecutor.KEY_VICE_ITEM);
1163+
parser.putQueryResult(arrayPath + "/" + i + "/" + name, obj); // 解决获取关联数据时requestObject里不存在需要的关联数据
11381164
}
11391165
}
11401166

APIJSONORM/src/main/java/apijson/orm/AbstractParser.java

+24-17
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ public JSONObject parseResponse(JSONObject request) {
537537
queryDepth = 0;
538538
executedSQLDuration = 0;
539539

540-
requestObject = onObjectParse(request, null, null, null, false);
540+
requestObject = onObjectParse(request, null, null, null, false, null);
541541

542542
onCommit();
543543
}
@@ -1081,17 +1081,18 @@ public JSONObject getStructure(@NotNull String table, String method, String tag,
10811081

10821082
// protected SQLConfig<T> itemConfig;
10831083
/**获取单个对象,该对象处于parentObject内
1084-
* @param request parentObject 的 value
1085-
* @param parentPath parentObject 的路径
1086-
* @param name parentObject 的 key
1087-
* @param arrayConfig config for array item
1088-
* @param isSubquery 是否为子查询
1089-
* @return
1090-
* @throws Exception
1091-
*/
1084+
* @param request parentObject 的 value
1085+
* @param parentPath parentObject 的路径
1086+
* @param name parentObject 的 key
1087+
* @param arrayConfig config for array item
1088+
* @param isSubquery 是否为子查询
1089+
* @param cache SQL 结果缓存
1090+
* @return
1091+
* @throws Exception
1092+
*/
10921093
@Override
1093-
public JSONObject onObjectParse(final JSONObject request
1094-
, String parentPath, String name, final SQLConfig<T> arrayConfig, boolean isSubquery) throws Exception {
1094+
public JSONObject onObjectParse(final JSONObject request, String parentPath, String name
1095+
, final SQLConfig<T> arrayConfig, boolean isSubquery, JSONObject cache) throws Exception {
10951096

10961097
if (Log.DEBUG) {
10971098
Log.i(TAG, "\ngetObject: parentPath = " + parentPath
@@ -1135,6 +1136,8 @@ public JSONObject onObjectParse(final JSONObject request
11351136
}
11361137
// 对象 - 设置 method
11371138
setOpMethod(request, op, name);
1139+
1140+
op.setCache(cache);
11381141
op = op.parse(name, isReuse);
11391142

11401143
JSONObject response = null;
@@ -1251,14 +1254,16 @@ public JSONObject onObjectParse(final JSONObject request
12511254
}
12521255

12531256
/**获取对象数组,该对象数组处于parentObject内
1257+
* @param request parentObject的value
12541258
* @param parentPath parentObject的路径
12551259
* @param name parentObject的key
1256-
* @param request parentObject的value
1260+
* @param isSubquery 是否为子查询
1261+
* @param cache SQL 结果缓存
12571262
* @return
12581263
* @throws Exception
12591264
*/
12601265
@Override
1261-
public JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery) throws Exception {
1266+
public JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery, JSONArray cache) throws Exception {
12621267
if (Log.DEBUG) {
12631268
Log.i(TAG, "\n\n\n onArrayParse parentPath = " + parentPath
12641269
+ "; name = " + name + "; request = " + JSON.toJSONString(request));
@@ -1355,23 +1360,25 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
13551360

13561361

13571362
//Table<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1358-
response = new JSONArray();
1363+
1364+
List<Join> joinList = onJoinParse(join, request);
13591365
SQLConfig<T> config = createSQLConfig()
13601366
.setMethod(requestMethod)
13611367
.setCount(size)
13621368
.setPage(page2)
13631369
.setQuery(query2)
13641370
.setCompat(compat)
13651371
.setTable(arrTableKey)
1366-
.setJoinList(onJoinParse(join, request));
1372+
.setJoinList(joinList);
13671373

13681374
JSONObject parent;
13691375

13701376
boolean isExtract = true;
13711377

1378+
response = new JSONArray();
13721379
//生成size个
13731380
for (int i = 0; i < (isSubquery ? 1 : size); i++) {
1374-
parent = onObjectParse(request, isSubquery ? parentPath : path, isSubquery ? name : "" + i, config.setType(SQLConfig.TYPE_ITEM).setPosition(i), isSubquery);
1381+
parent = onObjectParse(request, isSubquery ? parentPath : path, isSubquery ? name : "" + i, config.setType(SQLConfig.TYPE_ITEM).setPosition(i), isSubquery, null);
13751382
if (parent == null || parent.isEmpty()) {
13761383
break;
13771384
}
@@ -1386,7 +1393,7 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
13861393
@SuppressWarnings("unchecked")
13871394
List<JSONObject> list = fo == null ? null : (List<JSONObject>) fo.remove(AbstractSQLExecutor.KEY_RAW_LIST);
13881395

1389-
if (list != null && list.isEmpty() == false) {
1396+
if (list != null && list.isEmpty() == false && (joinList == null || joinList.isEmpty())) {
13901397
isExtract = false;
13911398

13921399
list.set(0, fo); // 不知道为啥第 0 项也加了 @RAW@LIST

APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -4504,7 +4504,7 @@ public String getSetString(RequestMethod method, Map<String, Object> content, bo
45044504
if (setString.isEmpty()) {
45054505
throw new IllegalArgumentException("PUT 请求必须在Table内设置要修改的 key:value !");
45064506
}
4507-
return (isClickHouse()?" ":" SET ") + setString;
4507+
return (isClickHouse() ? " " : " SET ") + setString;
45084508
}
45094509

45104510
/**SET key = concat(key, 'value')
@@ -6023,7 +6023,7 @@ public static String getRealKey(RequestMethod method, String originKey
60236023
return originKey;
60246024
}
60256025

6026-
String key = new String(originKey);
6026+
String key = originKey;
60276027
if (key.endsWith("$")) {//搜索 LIKE,查询时处理
60286028
String k = key.substring(0, key.length() - 1);
60296029
// key%$:"a" -> key LIKE '%a%'; key?%$:"a" -> key LIKE 'a%'; key_?$:"a" -> key LIKE '_a'; key_%$:"a" -> key LIKE '_a%'

APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java

+20-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public abstract class AbstractSQLExecutor<T extends Object> implements SQLExecut
3232
//是否返回 值为null的字段
3333
public static boolean ENABLE_OUTPUT_NULL_COLUMN = false;
3434
public static String KEY_RAW_LIST = "@RAW@LIST"; // 避免和字段命名冲突,不用 $RAW@LIST$ 是因为 $ 会在 fastjson 内部转义,浪费性能
35+
public static String KEY_VICE_ITEM = "@VICE@ITEM"; // 避免和字段命名冲突,不用 $VICE@LIST$ 是因为 $ 会在 fastjson 内部转义,浪费性能
3536

3637
private Parser<T> parser;
3738
@Override
@@ -406,6 +407,7 @@ public JSONObject execute(@NotNull SQLConfig<T> config, boolean unknownType) thr
406407
Log.d(TAG, "\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n execute while (rs.next()){ index = " + index + "\n\n");
407408

408409
JSONObject item = new JSONObject(true);
410+
JSONObject viceItem = null;
409411
JSONObject curItem = item;
410412
boolean isMain = true;
411413

@@ -537,6 +539,9 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
537539
columnIndexAndJoinMap[i - 1] = curJoin;
538540
}
539541

542+
//boolean isVice = false;
543+
//String viceName = null;
544+
540545
// 如果是主表则直接用主表对应的 item,否则缓存副表数据到 childMap
541546
Join prevJoin = columnIndexAndJoinMap == null || i < 2 ? null : columnIndexAndJoinMap[i - 2];
542547
if (curJoin != prevJoin) { // 前后字段不在同一个表对象,即便后面出现 null,也不该是主表数据,而是逻辑 bug 导致
@@ -556,6 +561,7 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
556561
}
557562
}
558563
}
564+
559565
String viceSql = viceConfig == null ? null : viceConfig.getSQL(false); //TODO 在 SQLConfig<T> 缓存 SQL,减少大量的重复生成
560566

561567
if (StringUtil.isEmpty(viceSql, true)) {
@@ -568,17 +574,28 @@ else if (curJoin.isOuterJoin() || curJoin.isAntiJoin()) {
568574
// 副表是按常规条件查询,缓存会导致其它同表同条件对象查询结果集为空 childMap.put(viceSql, new JSONObject()); // 缓存固定空数据,避免后续多余查询
569575
}
570576
else {
571-
curItem = childMap.get(viceSql);
577+
//isVice = true;
578+
String viceName = viceConfig.getTable() + (StringUtil.isEmpty(viceConfig.getAlias()) ? "" : ":" + StringUtil.isEmpty(viceConfig.getAlias()));
579+
if (viceItem == null) {
580+
viceItem = new JSONObject(true);
581+
}
582+
curItem = viceItem.getJSONObject(viceName);
583+
//curItem = childMap.get(viceSql);
572584
if (curItem == null) {
573585
curItem = new JSONObject(true);
574-
childMap.put(viceSql, curItem);
586+
//childMap.put(viceSql, curItem);
587+
viceItem.put(viceName, curItem);
575588
}
576589
}
577590
}
578591

579592
curItem = onPutColumn(config, rs, rsmd, index, curItem, i, curJoin, childMap); // isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
580593
}
581594

595+
if (viceItem != null) {
596+
item.put(KEY_VICE_ITEM, viceItem);
597+
}
598+
582599
resultList = onPutTable(config, rs, rsmd, resultList, index, item);
583600

584601
Log.d(TAG, "execute while (rs.next()) { resultList.put( " + index + ", result); " + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>> \n\n");
@@ -907,7 +924,7 @@ protected JSONObject onPutColumn(@NotNull SQLConfig<T> config, @NotNull ResultSe
907924
// 主表必须 put 至少一个 null 进去,否则全部字段为 null 都不 put 会导致中断后续正常返回值
908925
if (value != null) {
909926
table.put(label, value);
910-
} else{
927+
} else {
911928
if (join == null && table.isEmpty()) {
912929
table.put(label, null);
913930
} else if (ENABLE_OUTPUT_NULL_COLUMN) {

APIJSONORM/src/main/java/apijson/orm/ObjectParser.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public interface ObjectParser<T extends Object> {
2626
String getParentPath();
2727
ObjectParser<T> setParentPath(String parentPath);
2828

29+
ObjectParser<T> setCache(JSONObject cache);
30+
JSONObject getCache();
31+
32+
2933
/**解析成员
3034
* response重新赋值
3135
* @param name
@@ -67,10 +71,11 @@ public interface ObjectParser<T extends Object> {
6771
* @param index
6872
* @param key
6973
* @param value
74+
* @param cache SQL 结果缓存
7075
* @return
7176
* @throws Exception
7277
*/
73-
JSON onChildParse(int index, String key, JSONObject value) throws Exception;
78+
JSON onChildParse(int index, String key, JSONObject value, JSON cache) throws Exception;
7479

7580
/**解析赋值引用
7681
* @param path
@@ -164,5 +169,4 @@ public interface ObjectParser<T extends Object> {
164169
Map<String, Map<String, String>> getFunctionMap();
165170
Map<String, JSONObject> getChildMap();
166171

167-
168172
}

APIJSONORM/src/main/java/apijson/orm/Parser.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St
6666
JSONObject getStructure(String table, String method, String tag, int version) throws Exception;
6767

6868

69-
JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig<T> arrayConfig, boolean isSubquery) throws Exception;
69+
JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig<T> arrayConfig, boolean isSubquery, JSONObject cache) throws Exception;
7070

71-
JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery) throws Exception;
71+
JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery, JSONArray cache) throws Exception;
7272

7373
/**解析远程函数
7474
* @param key

0 commit comments

Comments
 (0)