2021SC@SDUSC
protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map<String, JSONObject> childMap) throws Exception {
List<Join> joinList = config.getJoinList();
if (joinList != null) {
SQLConfig jc;
SQLConfig cc;
for (Join j : joinList) {
if (j.isAppJoin() == false) {
Log.i(TAG, "executeAppJoin for (Join j : joinList) >> j.isAppJoin() == false >> continue;");
continue;
}
cc = j.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
if (cc == null) {
if (Log.DEBUG) {
throw new NullPointerException("服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据!");
}
continue;
}
jc = j.getJoinConfig();
//取出 "id@": "@/User/userId" 中所有 userId 的值
List<Object> targetValueList = new ArrayList<>();
JSONObject mainTable;
Object targetValue;
for (int i = 0; i < resultList.size(); i++) {
mainTable = resultList.get(i);
targetValue = mainTable == null ? null : mainTable.get(j.getTargetKey());
if (targetValue != null && targetValueList.contains(targetValue) == false) {
targetValueList.add(targetValue);
}
}
//替换为 "id{}": [userId1, userId2, userId3...]
jc.putWhere(j.getOriginKey(), null, false); // remove orginKey
jc.putWhere(j.getKey() + "{}", targetValueList, true); // add orginKey{}
jc.setMain(true).setPreparedValueList(new ArrayList<>());
boolean prepared = jc.isPrepared();
final String sql = jc.getSQL(false);
jc.setPrepared(prepared);
if (StringUtil.isEmpty(sql, true)) {
throw new NullPointerException(TAG + ".executeAppJoin StringUtil.isEmpty(sql, true) >> return null;");
}
long startTime = System.currentTimeMillis();
Log.d(TAG, "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
+ "\n executeAppJoin startTime = " + startTime
+ "\n sql = \n " + sql
+ "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
//执行副表的批量查询 并 缓存到 childMap
ResultSet rs = null;
try {
rs = executeQuery(jc);
int index = -1;
ResultSetMetaData rsmd = rs.getMetaData();
final int length = rsmd.getColumnCount();
JSONObject result;
String cacheSql;
while (rs.next()) { //FIXME 同时有 @ APP JOIN 和 < 等 SQL JOIN 时,next = false 总是无法进入循环,导致缓存失效,可能是连接池或线程问题
index ++;
Log.d(TAG, "\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n executeAppJoin while (rs.next()){ index = " + index + "\n\n");
result = new JSONObject(true);
for (int i = 1; i <= length; i++) {
result = onPutColumn(jc, rs, rsmd, index, result, i, null);
}
//每个 result 都要用新的 SQL 来存 childResultMap = onPutTable(config, rs, rsmd, childResultMap, index, result);
Log.d(TAG, "\n executeAppJoin while (rs.next()) { resultList.put( " + index + ", result); "
+ "\n >>>>>>>>>>>>>>>>>>>>>>>>>>> \n\n");
//缓存到 childMap
cc.putWhere(j.getKey(), result.get(j.getKey()), true);
cacheSql = cc.getSQL(false);
childMap.put(cacheSql, result);
Log.d(TAG, ">>> executeAppJoin childMap.put('" + cacheSql + "', result); childMap.size() = " + childMap.size());
}
}
finally {
if (rs != null) {
try {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
long endTime = System.currentTimeMillis();
Log.d(TAG, "\n\n executeAppJoin endTime = " + endTime + "; duration = " + (endTime - startTime)
+ "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n");
}
}
}
这一段代码是子查询的SQL执行
首先是分析jsonobject,处理其中的各种id,转换为mysql语句;
再执行查询。
protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
, final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map<String, JSONObject> childMap) throws Exception {
if (rsmd.getColumnName(columnIndex).startsWith("_")) {
Log.i(TAG, "select while (rs.next()){ ..."
+ " >> rsmd.getColumnName(i).startsWith(_) >> continue;");
return table;
}
//已改为 rsmd.getTableName(columnIndex) 支持副表不传 @column , 但如何判断是副表?childMap != null
// String lable = rsmd.getColumnLabel(columnIndex);
// int dotIndex = lable.indexOf(".");
String lable = getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap);
String childTable = childMap == null ? null : rsmd.getTableName(columnIndex); //dotIndex < 0 ? null : lable.substring(0, dotIndex);
JSONObject finalTable = null;
String childSql = null;
SQLConfig childConfig = null;
if (childTable == null) {
finalTable = table;
}
else {
// lable = column;
//<sql, Table>
List<Join> joinList = config.getJoinList();
if (joinList != null) {
for (Join j : joinList) {
childConfig = j.isAppJoin() ? null : j.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
if (childConfig != null && childTable.equalsIgnoreCase(childConfig.getSQLTable())) {
childConfig.putWhere(j.getKey(), table.get(j.getTargetKey()), true);
childSql = childConfig.getSQL(false);
if (StringUtil.isEmpty(childSql, true)) {
return table;
}
finalTable = (JSONObject) childMap.get(childSql);
break;
}
}
}
}
Object value = getValue(config, rs, rsmd, tablePosition, table, columnIndex, lable, childMap);
if (value != null) {
if (finalTable == null) {
finalTable = new JSONObject(true);
childMap.put(childSql, finalTable);
}
finalTable.put(lable, value);
}
return table;
}
此方法的作用是插入表格,将结果集的值制成表格;
public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable) {
try {
String column = rsmd.getColumnTypeName(position);
//TODO CHAR和JSON类型的字段,getColumnType返回值都是1 ,如果不用CHAR,改用VARCHAR,则可以用上面这行来提高性能。
//return rsmd.getColumnType(position) == 1;
if (column.toLowerCase().contains("json")) {
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
// List<String> json = config.getJson();
// return json != null && json.contains(lable);
return false;
}
判断是否为JSON类型