1. 核心原理:为什么XML容不下<和>?
XML(可扩展标记语言)的语法结构是靠“标签”来支撑的,而标签的定义符号就是尖括号< >。
-
解析器的视角:当XML解析器从左往右扫描文件时,一旦遇到
<,它会下意识地认为:“注意!一个新的标签要开始了! ” -
冲突点:
- 如果你写
order_time < #{end}。 - 解析器读到
<时,会期待后面跟着一个标签名(比如if、where)。 - 结果发现后面是个空格或者
#{,解析器就懵了,直接报**Malformed XML(XML格式错误)** 。
- 如果你写
注意: 其实在 XML 规范中,
>(大于号)在大多数情况下是可以直接写的,不会报错。但在 MyBatis 中,为了保持代码风格统一和避免可能的解析歧义,我们通常习惯把<并>都进行转义。
2. 解决方案一:转义字符(实体引用)
这是你在代码中正在使用的方法,也是最推荐的方法。
常用转义字符对照表(建议向下背,尤其是前两个):
| 符号 | 转义写法(实体引用) | 记忆技巧 |
|---|---|---|
< | < | 小于 ( 小于) |
> | > | 大于 T han (大于) |
& | & | & 和号(&) |
' | ' | Apos trope (单引号) |
" | " | 报价(双引号) |
应用场景:
配合if等动态SQL标签使用时,转义字符是最佳选择。
XML
<if test="end != null">
and order_time <= #{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:必须用转义字符 ( <, >)
当你的 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>