在前一篇文章通过拦截器Interceptor优化Mybatis的in查询中,我们已经解决了mybatis查询中in()空列表的情况。
但是由于foreach标签中list为空导致的情况并非只有in()空列表一种,另一种常见的情况会发生在批量插入数据,如下所示:
INSERT INTO table1(
column1
) VALUES
<foreach collection="list" item="item" index="index" separator="," >
(
#{item.column1}
)
</foreach>
所以我们决定在in()的基础上,再次升级,支持values()的情况,这基本上也覆盖了foreach标签内list为空所会导致的sql出错的问题
主要修改的是isHaveEmptyList的函数,具体如下所示:
/**
* 去除字符中的干扰项
*
* @param sql
* @return
*/
private static String removeInterference(String sql,String keyWorld) {
Pattern pattern = Pattern.compile("\".*?\"");
Matcher matcher = pattern.matcher(sql);
while (matcher.find()) {
String replaceWorld = matcher.group();
if (StringUtils.containsIgnoreCase(replaceWorld, keyWorld)) {
sql = sql.replace(replaceWorld, "\"\"");
}
}
return sql;
}
/**
* 判断是否存在空list
* @param sql
* @return
*/
private static Boolean isHaveEmptyList(String sql) {
List<Integer> indexList = Lists.newArrayList();
String keyWorld = (StringUtils.containsIgnoreCase(sql, "insert")) ? "values" : "in";
sql = removeInterference(sql, keyWorld);
Pattern pattern = Pattern.compile("\\s(?i)" + keyWorld);
Matcher matcher = pattern.matcher(sql);
while (matcher.find()) {
indexList.add(matcher.end());
}
return checkHaveEmptyList(sql, indexList);
}
/**
* 判断sql在indexList的每个index后是否存在存在空列表的情况
* @param sql
* @param indexList keyWorld在sql中的位置
* @return
*/
private static Boolean checkHaveEmptyList(String sql,List<Integer> indexList) {
Boolean isHaveEmptyList = Boolean.FALSE;
Pattern p2 = Pattern.compile("(?<=\\()[.\n]*?(?=\\))");
for (Integer index : indexList) {
String subSql = sql.substring(index);
if (StringUtils.isEmpty(subSql)) {
isHaveEmptyList = Boolean.TRUE;
break;
}
Boolean flag = subSql.startsWith("(")
|| subSql.startsWith(" ")
|| subSql.startsWith("\n")
|| subSql.startsWith("\r");
if (!flag) {
continue;
}
subSql = subSql.trim();
if (!subSql.startsWith("(")) {
isHaveEmptyList = Boolean.TRUE;
break;
}
Matcher m2 = p2.matcher(subSql);
if (m2.find()) {
if (StringUtils.isBlank(m2.group())) {
isHaveEmptyList = Boolean.TRUE;
break;
}
}
}
return isHaveEmptyList;
}
主要是通过keyworld来识别是in()的情况还是values()的情况,然后统一使用checkHaveEmptyList方法再去判断是否存在空列表。
如果还有其他情况,欢迎大家补充,也欢迎大家给我提出宝贵的建议。
网友评论