//错误
<update id="updateBatch" parameterType="java.util.List">
        <foreach collection="list" item="item" index="index" separator=";">
            update manage
            <set>
                <if test="item.userName != null">
                    userName=#{userName},
                </if>
                <if test="item.passWord != null">
                    passWord=#{passWord},
                </if>
                <if test="item.realName != null">
                    realName=#{realName}
                </if>
            </set>
            where 1=1
            <if test="item.id!=null">
                and id=#{item.id}
            </if>
        </foreach>
    </update>

//正确
<update id="updateBatch" parameterType="java.util.List">
        <foreach collection="list" item="item" index="index" separator=";">
            update manage
            <set>
                <if test="item.userName != null">
                    userName = #{item.userName},
                </if>
                <if test="item.passWord != null">
                    passWord = #{item.passWord},
                </if>
                <if test="item.realName != null">
                    realName = #{item.realName}
                </if>
            </set>
            where 1=1
            <if test="item.id != null">
               and id = #{item.id}
            </if>
        </foreach>
    </update>

核心结论

这些空格大部分是【必要的】,它们直接影响到最终生成的SQL语句的正确性和可读性。 第二段代码在正确性上更优,主要是因为它修正了第一段代码中一个严重的错误


一、逐行对比分析

让我们把两段代码的关键不同点拆解出来:

1. 赋值语句右边的空格(关键错误修正)

  • 第一段代码(错误)

    xml
    userName=#{userName},
    • 问题: #{userName} 前面没有空格。这会导致生成的SQL语句变成 userName=John,,这是一个严重的语法错误。SQL要求赋值操作符两边必须有空格(虽然不是所有数据库都强制要求,但这是标准SQL约定,没有空格非常容易出错)。

  • 第二段代码(正确)

    xml
    userName = #{item.userName},
    • 修正: = 两边都有空格,生成的SQL是 userName = 'John',,这是完全符合SQL语法的标准写法。

2. 参数引用的完整性(关键错误修正)

  • 第一段代码(错误)

    xml
    #{userName}
    • 问题: 它缺少了 item. 前缀。在 MyBatis 的 <foreach> 循环中,每个元素用 item="item" 指定了别名。要访问当前遍历对象的属性,必须使用 item.属性名。这里写 #{userName},MyBatis 会去查找一个叫 userName 的顶级参数,而不是你传入的List中某个对象的属性。这会导致参数绑定失败,值变为 null

  • 第二段代码(正确)

    xml
    #{item.userName}
    • 修正: 正确地引用了当前循环对象 item 的 userName 属性。

3. WHERE 和 AND 前的空格(必要且重要)

  • 第一段代码(有风险)

    xml
    where 1=1
    <if...>and id=#{item.id}</if>
    • 分析: where 1=1 和后面的 and id... 拼接时,会生成 where 1=1and id=1虽然 1=1and 在大多数数据库中被解析为 1=1 and(因为and是关键字),但这种依赖数据库自动识别的做法是有风险的,非常不规范

  • 第二段代码(最佳实践)

    xml
    where 1=1
    <if...> and id = #{item.id}</if>
    • 修正: 在 and 前面显式地加上了一个空格。这样就能确保生成标准的 where 1=1 and id = 1。这是非常良好且必要的习惯

4. 其他空格(主要为了可读性)

像 item.id != null 等表达式中的空格,以及标签内的一些换行和缩进,主要是为了让XML代码本身更清晰、更易读,对最终生成的SQL没有影响。MyBatis在解析动态SQL标签(<if><set>等)时,会智能地处理掉多余的空白字符,只保留SQL语句本身必要的空格。


二、最终生成的SQL对比

假设我们传入的List包含一个对象:{id: 1, userName: "Admin"}

  • 第一段错误代码生成的SQL

    sql
    update manage set userName=, passWord=?, realName=? where 1=1and id=?;

    这是一条完全错误的SQL! 原因:

    1. userName= 后面没有空格,语法怪异。

    2. #{userName} 因引用错误导致值为 null,所以 userName= 后面直接是逗号,语法错误。

    3. where 1=1and id=? 缺少空格,不规范。

  • 第二段正确代码生成的SQL

    sql
    update manage set userName = 'Admin', where 1=1 and id = 1;

    这是一条语法正确、清晰明了的SQL。(注意:即使多了一个逗号,<set> 标签也会负责去掉它)。

三、总结

 
 
差异点 第一段代码 第二段代码 重要性
赋值空格 (=) userName=#{...} userName = #{...} 【关键】:缺少空格会导致SQL语法错误或不规范。
参数引用 #{userName} #{item.userName} 【致命】:缺少 item. 会导致参数绑定失败,值为null。
条件空格 (and) and id=#{...} and id = #{...} 【重要】:显式的空格是良好实践,保证SQL100%正确。
代码格式 空格较少,紧凑 空格较多,清晰 【一般】:影响开发者阅读代码的体验,不影响SQL生成。

结论:第二段代码不仅仅是“多了些空格”,而是修正了第一段代码中存在的两个严重错误(参数引用和SQL语法),是正确、可靠且符合规范的写法。 在编写MyBatis动态SQL时,保证SQL语句本身格式的正确性至关重要。

 

posted on 2025-09-20 10:16  fafrkvit  阅读(17)  评论(0)    收藏  举报