MyBatis XML转义规则:避免SQL语句解析错误的解决方案

深入解析MyBatis XML中特殊字符的转义规则,通过实例说明为什么需要转义以及如何正确使用

优兔GOGO
2025年11月6日
技术分享
MyBatisXML转义SQL大于等于小于等于特殊字符

MyBatis XML转义规则:避免SQL语句解析错误的解决方案

在MyBatis的XML映射文件中编写SQL时,经常会遇到XML解析错误。明明SQL语法是正确的,为什么MyBatis会报错?问题出在XML的特殊字符上。

XML有5个预定义的实体字符,它们有特殊含义,不能直接使用。当我们在SQL中使用<>&等字符时,XML解析器会误以为这是XML标签或实体,导致解析失败。理解这些转义规则,可以避免很多不必要的错误。

XML特殊字符转义对照表

在MyBatis XML中,以下字符需要转义:

字符XML转义写法适用场景
<&lt;小于号,小于比较
<=&lt;=小于等于比较
>&gt;大于号,大于比较
>=&gt;=大于等于比较
&&amp;与符号,位运算或逻辑运算
"&quot;双引号,字符串
'&apos;单引号,字符串

转义的底层原理

XML解析器在解析文档时,会按照XML规范处理特殊字符:

  1. <字符:XML解析器认为这是标签的开始,如<if><select>
  2. >字符:XML解析器认为这是标签的结束
  3. &字符:XML解析器认为这是实体的开始,如&lt;&gt;

如果在SQL中直接使用这些字符,解析器会尝试将它们当作XML语法来处理,从而导致解析错误。

例如,当写WHERE age >= 18时,XML解析器看到>会认为这是某个标签的结束,但前面没有对应的开始标签,就会报错。

实战示例

示例1:基础比较查询

查询金额大于等于1000的订单:

<select id="findOrdersByAmount" resultType="Order">
    SELECT * FROM orders
    WHERE amount &gt;= 1000
</select>

为什么这么写&gt;=>=的XML转义形式,XML解析器会将其还原为>=后再传给数据库。

示例2:范围查询

查询年龄在18到65之间的用户:

<select id="findUsersByAgeRange" resultType="User">
    SELECT * FROM users
    WHERE age &gt;= 18
    AND age &lt;= 65
</select>

为什么这么写:两个比较运算符都需要转义,&gt;=表示>=&lt;=表示<=

示例3:动态SQL中的转义

根据条件动态添加查询条件:

<select id="searchProducts" resultType="Product">
    SELECT * FROM products
    WHERE 1=1
    <if test="minPrice != null">
        AND price &gt;= #{minPrice}
    </if>
    <if test="maxPrice != null">
        AND price &lt;= #{maxPrice}
    </if>
    <if test="stock != null">
        AND stock &gt; 0
    </if>
</select>

为什么这么写:在<if>标签的test属性中,如果使用>=,XML解析器会误解析。在SQL语句中也需要转义,否则会报错。

示例4:UPDATE语句中的转义

更新价格低于某个值的商品:

<update id="updateLowPriceProducts">
    UPDATE products
    SET discount = 0.8
    WHERE price &lt; 50
</update>

为什么这么写:UPDATE语句中的WHERE条件同样需要转义,&lt;表示<

示例5:DELETE语句中的转义

删除创建时间早于某个日期的记录:

<delete id="deleteOldRecords">
    DELETE FROM logs
    WHERE create_time &lt;= #{cutoffDate}
</delete>

为什么这么写:DELETE语句中的比较运算符同样需要遵循XML转义规则。

示例6:复杂查询中的转义

多表关联查询,包含多个比较条件:

<select id="findComplexOrders" resultType="OrderDTO">
    SELECT o.*, u.name, p.product_name
    FROM orders o
    JOIN users u ON o.user_id = u.id
    JOIN products p ON o.product_id = p.id
    WHERE o.amount &gt;= #{minAmount}
    AND o.amount &lt;= #{maxAmount}
    AND o.create_time &gt;= #{startTime}
    AND o.status = 'completed'
</select>

为什么这么写:即使SQL语句很长,只要包含<><=>=等字符,都需要转义。

示例7:子查询中的转义

使用子查询进行比较:

<select id="findTopUsers" resultType="User">
    SELECT * FROM users
    WHERE score &gt;= (
        SELECT AVG(score) FROM users
    )
</select>

为什么这么写:子查询中的比较运算符同样需要转义,不能因为是子查询就省略转义。

CDATA区域的使用

除了转义字符,还可以使用CDATA区域来避免转义:

CDATA示例1:简单查询

<select id="findUsers" resultType="User">
    <![CDATA[
        SELECT * FROM users
        WHERE age >= 18 AND age <= 65
    ]]>
</select>

为什么这么写:CDATA区域内的内容会被XML解析器当作纯文本处理,不需要转义。但要注意参数占位符的处理。

CDATA示例2:与动态SQL结合

<select id="search" resultType="Product">
    SELECT * FROM products
    WHERE 1=1
    <if test="minPrice != null">
        <![CDATA[ AND price >= ]]> #{minPrice}
    </if>
    <if test="maxPrice != null">
        <![CDATA[ AND price <= ]]> #{maxPrice}
    </if>
</select>

为什么这么写:CDATA区域不能包含参数占位符#{},所以需要将占位符放在CDATA外面。这样既避免了转义,又能正确使用参数。

转义字符 vs CDATA

对比项转义字符CDATA
可读性&lt;&gt;不够直观SQL保持原样,更易读
使用场景简单SQL,少量运算符复杂SQL,大量运算符
参数处理可以直接使用#{}需要小心处理占位符
维护成本转义字符需要记忆SQL更接近原生写法

常见错误分析

错误示例1:直接使用比较运算符

<!-- 错误写法 -->
<select id="findUsers">
    SELECT * FROM users
    WHERE age >= 18
</select>

错误原因:XML解析器看到>会认为这是标签的结束,但前面没有对应的开始标签。

正确写法

<select id="findUsers">
    SELECT * FROM users
    WHERE age &gt;= 18
</select>

错误示例2:test属性中忘记转义

<!-- 错误写法 -->
<if test="age >= 18">
    AND age >= 18
</if>

错误原因:test属性中的>=也需要转义,XML解析器会先解析test属性。

正确写法

<if test="age &gt;= 18">
    AND age &gt;= 18
</if>

错误示例3:CDATA中嵌套参数

<!-- 错误写法 -->
<if test="age != null">
    <![CDATA[ AND age >= #{age} ]]>
</if>

错误原因:CDATA区域内的#{}不会被MyBatis解析,会被当作普通文本。

正确写法

<if test="age != null">
    <![CDATA[ AND age >= ]]> #{age}
</if>

实际开发中的建议

  1. 统一规范:在团队中统一使用转义字符或CDATA,保持代码风格一致。
  2. IDE插件:使用支持MyBatis的IDE插件,可以自动提示转义字符。
  3. 代码审查:在代码审查时,注意检查特殊字符的转义是否正确。
  4. 测试验证:编写单元测试,验证包含比较运算符的SQL是否正确执行。
  5. 文档记录:在项目文档中记录转义规则,方便团队成员查阅。

掌握MyBatis XML转义规则,可以避免很多解析错误,提高开发效率。选择转义字符还是CDATA,要根据具体场景和团队规范来决定。


🔗 相关工具

  • 本文介绍的规则适用于所有MyBatis项目,建议使用支持MyBatis的IDE插件辅助开发