Mybatis中foreach标签内list为空的解决方案

作者: 逍遥jc | 来源:发表于2017-12-05 16:20 被阅读0次

在前一篇文章通过拦截器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方法再去判断是否存在空列表。

如果还有其他情况,欢迎大家补充,也欢迎大家给我提出宝贵的建议。

相关文章

网友评论

    本文标题:Mybatis中foreach标签内list为空的解决方案

    本文链接:https://www.haomeiwen.com/subject/chucixtx.html