一、文章引出原因
某天在完成项目中的一个小功能后进行自测的时候,发现存在一个很奇怪的 bug --- 最终执行的 SQL 与我所期望的 SQL 不一致,有一个 if 分支在我不传特定参数的情况下被拼接在最终的 SQL 上。
①定义在 XML 文件中的 SQL 语句
<select id="balanceByUserIds" parameterType="xxx.BalanceReqVO"
resultType="xxx.Balance">
select * from balance
<where>
<if test="dataOrgCodes != null and dataOrgCodes.size > 0">
and data_org_code in
<foreach collection="dataOrgCodes" open="(" separator="," close=")" item="dataOrgCode">
#{dataOrgCode}
</foreach>
</if>
<if test="dataOrgCode != null and dataOrgCode != ''">
and data_org_code = #{dataOrgCode}
</if>
</where>
</select>
复制代码
②传进来的参数
{
"dataOrgCodes":["6","2"]
}
复制代码
③Mybatis 打印执行的 SQL
SELECT
*
FROM
balance
WHERE
data_org_code IN (?, ?)
AND data_org_code = ?
复制代码
打印的执行参数
{
"dataOrgCodes":["6","2"]
}
复制代码
二、存在的问题
学过 Mybatis 的人应该一样就看出来了,这个 SQL 不对劲,多了一些不该有的东西。按照我们的理解,最终的执行的 SQL 应该是
SELECT
*
FROM
balance
WHERE
data_org_code IN (?, ?)
复制代码
但 mybatis 执行的 SQL 多了一点语句---AND data_org_code = ?
在出现这个问题后我反复进行 debug,确定了自己传进来的参数没有什么问题,也没有什么拦截器添加多余的参数。
三、分析 SQL 生成过程
在确定编写 XML 文件的 if 标签的内容以及传进来的参数无误后,排除了参数导致问题。那么除了这个可能外,问题就可能出现在 SQL 的解析上,也就是 SQL 的生成那里。那么我们定位到 SQL 的生成地方, DynamicSqlSource#getBoundSql(我们查询的参数对象)方法
// Configuration是Mybatis核心类,rootSqlNode 根SQL节点是我们定义在XML中的SQL语句。
//(例如<select>rootSqlNode</sselect>, 标签中间的内容就是 rootSqlNode)
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
this.configuration = configuration;
this.rootSqlNode = rootSqlNode;
}
public BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);
............................