在 MyBatis 中,我们都知道 mapper.xml 是使用了 XML 的语法,所以会出现有一些特殊的字符不能直接被转义,在编译解析时,会导致编译出错。例如:’<’ 和 ‘&’ 字符在 XML 元素中都是非法的

疑问?

  1. <![CDATA[ ]]> 是什么东东?
  2. 在 MyBatis 中使用 <![CDATA[ ]]> 不能解决的问题?
  3. 如何解决问题?

<![CDATA[ ]]> 是什么东东?

术语 CDATA 是不应该由 XML 解析器解析的文本数据。
像 “<” 和 “&” 字符在 XML 元素中都是非法的。
“<” 会产生错误,因为解析器会把该字符解释为新元素的开始。
“&” 会产生错误,因为解析器会把该字符解释为字符实体的开始。
某些文本,MyBatis,判断大小:”SELECT * FROM USER U WHERE U.AGE < 20 “。为了避免错误,可以将脚本代码定义为 CDATA。

CDATA 部分中的所有内容都会被解析器忽略。
CDATA 部分由 “<![CDATA[“ 开始,由 “]]>” 结束:

1
2
3
4
5
<SELECT id="queryUser" resultType="com.myk.entity.User">
<![CDATA[
SELECT * FROM USER U WHERE U.AGE < 20
]]>
</SELECT>

在上面的实例中,解析器会忽略 CDATA 部分中的所有内容。
那么 <![CDATA[ ]]> 部分中的内容将被视为是一个文本数据。

关于 CDATA 部分的注释:
CDATA 部分不能包含字符串 “]]>”。也不允许嵌套的 CDATA 部分。
标记 CDATA 部分结尾的 “]]>” 不能包含空格或换行。

在 MyBatis 中使用 <![CDATA[ ]]> 不能解决的问题

根据上边的解释,应该都知道使用 <![CDATA[ ]]> 会有怎样的效果,那为什么还有不能解决的问题呢?
都知道 MyBatis 中有很多的运算标签,如 <if></if><foreach></foreach><where></where><choose></choose> 等标签。这里既然提到了这些标签,那么就说明 <![CDATA[]]> 与这些标签一起使用,在执行的时候将会出现问题。,这是为什么呢?
因为在 MyBatis 中,解析器解析到这些标签的时候,会单独进行运算封装。而当这些标签被 <![CDATA[ ]]> 标记为文本内容之后,不会被解析器解析,而是将 <![CDATA[ ]]> 标记的内容当成是一条完整的 SQL 语句,进行执行操作,而这条被标记的 SQL 很明显就是有语法问题的,所以执行就是抛异常。如:

1
2
3
4
5
6
7
8
9
10
<SELECT id="queryUser" resultType="com.myk.entity.User">
<![CDATA[
SELECT * FROM USER U WHERE U.AGE &lt; 20
AND
U.userId IN
<foreach collection="userIdList" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
]]>
</SELECT>

以上代码会出现两个问题:

  1. SQL 中的 &lt; 不会被转义为 ‘<’ 符号
  2. SQl 中的 <foreach></foreach> 标签不会被解析执行,而是当成文本内容

SQL 被解析之后是这样的:
SELECT * FROM USER U WHERE U.AGE &lt; 20 AND U.userId IN <foreach collection="userIdList" item="userId" open="(" close=")" separator=","> #{userId} </foreach>

解决 MyBatis 中使用 <![CDATA[ ]]> 的问题

目前我有两种想法可以使用

精准定位

什么叫精准定位呢?即哪里需要,就标记哪里,最大限度的减少被 <![CDATA[ ]]> 标记的范围,减少出错的可能。如:

1
2
3
4
5
6
7
8
9
10
<SELECT id="queryUser" resultType="com.myk.entity.User">
<![CDATA[
SELECT * FROM USER U WHERE U.AGE < 20
]]>
AND
U.userId IN
<foreach collection="userIdList" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
</SELECT>

最后解析出来的 SQL :SELECT * FROM USER U WHERE U.AGE < 20 AND userId IN ('')

SQL全包裹

全包裹,顾名思义就是 <![CDATA[ ]]> 标记整条 SQL ,如果必须使用这种方式,那么 SQL 中就不能出现 MyBatis 的运算标签,如:

1
2
3
4
5
6
7
<SELECT id="queryUser" resultType="com.myk.entity.User">
<![CDATA[
SELECT * FROM USER U WHERE U.AGE < 20
AND
U.userId = #{userId}
]]>
</SELECT>

最后解析出来的 SQL :SELECT * FROM USER U WHERE U.AGE < 20 AND U.userId = #{userId}

最后更新: 2019年10月12日 20:21

原始链接: https://maiyikai.github.io/2019/07/26/1564117346/

× ~谢谢大爷~
打赏二维码