MyBatis XML中使用“<”或者”>“导致错误

8 阅读2分钟

1. 核心原理:为什么XML容不下<>

XML(可扩展标记语言)的语法结构是靠“标签”来支撑的,而标签的定义符号就是尖括号< >

  • 解析器的视角:当XML解析器从左往右扫描文件时,一旦遇到<,它会下意识地认为:“注意!一个新的标签要开始了! ​​”

  • 冲突点

    • 如果你写order_time < #{end}
    • 解析器读到<时,会期待后面跟着一个标签名(比如ifwhere)。
    • 结果发现后面是个空格或者#{,解析器就懵了,直接报**Malformed XML(XML格式错误)** 。

注意: 其实在 XML 规范中,>(大于号)在大多数情况下是可以直接写的,不会报错。但在 MyBatis 中,为了保持代码风格统一和避免可能的解析歧义,我们通常习惯把<>都进行转义。


2. 解决方案一:转义字符(实体引用)

这是你在代码中正在使用的方法,也是最推荐的方法。

常用转义字符对照表(建议向下背,尤其是前两个):

符号转义写法(实体引用)记忆技巧
<&lt;小于 ( 小于)
>&gt;大于 T han (大于)
&&amp;& 和号(&)
'&apos;Apos trope (单引号)
"&quot;报价(双引号)

应用场景:

配合if等动态SQL标签使用时,转义字符是最佳选择。

XML

<if test="end != null">
    and order_time &lt;= #{end}
</if>

3.解决方案二:CDATA区块

CDATA全称为字符数据(Character Data)。

语法: <![CDATA[ 你的内容 ]]>

你告诉XML解析器:“在这个方括号里的所有内容,你别管它是啥,直接当成纯文本(字符串)处理,不要尝试解析里面的标签! ”

应用场景:

当 SQL 语句特别长,或者包含大量特殊符号(比如复杂的数学运算、JSON 字符串)时,用 CDATA 使得代码看起来更原始的 SQL,本质性更强。

XML

<![CDATA[
    SELECT * FROM orders WHERE id <= 100 AND amount >= 50
]]>

4. 进阶:什么时候用哪种?(MyBatis 最佳实践)

这是一个很多新手都会困扰的问题,给你一个简单的判断标准:

✅ 情况 A:必须用转义字符 ( &lt;, &gt;)

当你的 SQL 语句中夹杂着 MyBatis 的动态标签(如<if>, <foreach>, <where>)时。

错误示范(CDATA 包裹了标签):

XML

<![CDATA[
    SELECT * FROM orders
    <where>   <-- 错误!XML解析器会忽略这个标签,导致 SQL 报错
        <if test="status != null">
            status = #{status}
        </if>
    </where>
]]>

原因:CDATA里的东西没有被解析,所以<if>标签失效了,拼接到SQL里到底是哪个字符,数据库看不懂。

✅ 情况B:推荐用CDATA

当你的 SQL 是纯静态的,或者虽然有#{}参数,但不包含任何 XML 标签时。

XML

<select id="getById" resultType="User">
    <![CDATA[
        SELECT * FROM user WHERE age <= #{age}
    ]]>
</select>