You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MyBatis SQL片段参数未正确替换问题咨询

问题描述

编写了如下MyBatis SQL片段:

<sql id="day">
    <choose>
        <when test="${property} == 'day'">
            substring(datachange_createtime, 1, 10)
        </when>
        <otherwise>
            ${property}
        </otherwise>
    </choose>
</sql>

并通过如下方式引用该片段:

select * from my_table
<if test="groupBy != null">
    group by
    <foreach collection="groupBy" item="groupByAttr" separator=",">
        <include refid="day">
            <property name="property" value="groupByAttr"/>
        </include>
    </foreach>
</if>

执行时出现异常:MyBatis未将property替换为实际参数,而是直接输出groupByAttr,生成的SQL为:

select * from my_table group by groupByAttr

若将otherwise分支中的${property}改为#{${property}},会生成预编译SQL:

select * from my_table group by ?

虽结果正确但不需要预编译形式。怀疑test与otherwise分支的参数替换行为存在差异,请问这是Bug还是使用错误?该如何解决?

原因分析

这不是MyBatis的Bug,是对<include>标签的property替换逻辑理解有误:

  • <include>的property属于静态文本替换,在SQL解析的早期阶段执行,此时foreach的item变量(groupByAttr)还未被解析为实际的字段值,所以${property}会被直接替换成字符串groupByAttr。
  • 而<when>标签的test属性是OGNL表达式,在运行时(参数传入后)才解析:此时${property}先被替换成字符串groupByAttr,OGNL再从当前上下文取出groupByAttr变量的实际值进行判断,所以test分支能正常工作。
解决方法

提供两种可行方案:

方案1:逻辑内联(推荐,代码更直观)

直接将<sql>片段的逻辑移到foreach内部,避免<include>的静态替换限制:

select * from my_table
<if test="groupBy != null">
    group by
    <foreach collection="groupBy" item="groupByAttr" separator=",">
        <choose>
            <when test="groupByAttr == 'day'">
                substring(datachange_createtime, 1, 10)
            </when>
            <otherwise>
                ${groupByAttr}
            </otherwise>
        </choose>
    </foreach>
</if>

方案2:保留<sql>片段复用

修改<sql>片段,通过OGNL动态解析变量,让property的值作为变量名从上下文获取实际字段:

<sql id="day">
    <choose>
        <when test="_parameter[property] == 'day'">
            substring(datachange_createtime, 1, 10)
        </when>
        <otherwise>
            ${_parameter[property]}
        </otherwise>
    </choose>
</sql>

引用方式保持不变即可,这样${_parameter[property]}会先解析property的值(即groupByAttr),再从当前参数上下文取出该变量对应的实际字段名,生成正确的非预编译SQL。

内容的提问来源于stack exchange,提问作者Expressway Retrograding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:55:18