你关注的是 MyBatis 的 mapper.xml 中如何正确处理「大于等于(>=)」和「小于等于(<=)」,以及相关的使用技巧(包括固定写法和动态优化),下面详细拆解:
一、核心问题:为什么不能直接在 mapper.xml 中写 >=、<=?
因为 <、> 是 XML 语言的特殊字符 (用于定义标签,如 <where>、<if>),直接写 zone_spacing >= #{zoneSpacingMin} 会导致 XML 解析器报错,无法识别该语法,因此需要通过「转义」或「CDATA 包裹」两种方式规避。
二、mapper.xml 中 >=、<= 的两种正确固定写法(常用)
写法1:使用 <![CDATA[]]> 包裹(推荐,直观易懂)
CDATA 块的作用是告诉 XML 解析器:「块内的内容是纯文本,无需解析标签,直接原样保留」,适合所有特殊字符场景。
xml
<select id="getTrafficZoneFlow" resultMap="TrafficZoneInfoSpaceingResultMap">
select
zone_id,
target_zone_id,
zone_spacing,
project_plan_id
from
traffic_zone_spacing
<where>
1=1
<if test="zoneId != null">
and zone_id = #{zoneId}
</if>
<if test="targetZoneId != null">
and target_zone_id = #{targetZoneId}
</if>
<!-- 大于等于(>=):用 CDATA 包裹 -->
<if test="zoneSpacingMin != null">
and zone_spacing <![CDATA[>=]]> #{zoneSpacingMin}
</if>
<!-- 小于等于(<=):用 CDATA 包裹 -->
<if test="zoneSpacingMax != null">
and zone_spacing <![CDATA[<=]]> #{zoneSpacingMax}
</if>
</where>
</select>
写法2:使用 XML 转义字符替换(兼容所有XML解析器)
将 >=、<= 替换为 XML 预定义的转义字符,也能避免解析报错,常用转义对应关系如下:
| 运算符 | 含义 | XML 转义字符 |
|---|---|---|
> |
大于 | > |
>= |
大于等于 | >= |
< |
小于 | < |
<= |
小于等于 | <= |
& |
与 | & |
" |
双引号 | " |
对应 SQL 示例:
xml
<select id="getTrafficZoneFlow" resultMap="TrafficZoneInfoSpaceingResultMap">
select
zone_id,
target_zone_id,
zone_spacing,
project_plan_id
from
traffic_zone_spacing
<where>
1=1
<if test="zoneId != null">
and zone_id = #{zoneId}
</if>
<if test="targetZoneId != null">
and target_zone_id = #{targetZoneId}
</if>
<!-- 大于等于(>=):使用转义字符 >= -->
<if test="zoneSpacingMin != null">
and zone_spacing >= #{zoneSpacingMin}
</if>
<!-- 小于等于(<=):使用转义字符 <= -->
<if test="zoneSpacingMax != null">
and zone_spacing <= #{zoneSpacingMax}
</if>
</where>
</select>
三、进阶:将 >=、<= 改为动态变量(灵活切换运算符,呼应你之前的需求)
如果需要将固定的 >=、<= 改为可动态切换的变量(支持 >、>=、<、<=),核心要点如下:
- 运算符必须用
${}拼接(#{}会加引号,导致 SQL 语法错误)。 - 用
<![CDATA[${运算符变量}]]>包裹${},避免 XML 解析报错。 - Java 层做白名单校验,防止 SQL 注入。
完整示例(动态运算符)
1. DTO 新增运算符参数(带白名单校验)
java
import java.util.Arrays;
public class TrafficZoneFlowQueryDTO {
private Integer zoneId;
private Integer targetZoneId;
private Integer zoneSpacingMin;
private Integer zoneSpacingMax;
// 新增:小于等于/小于 运算符(默认 <=)
private String zoneSpacingMaxOp = "<=";
// 新增:大于等于/大于 运算符(默认 >=)
private String zoneSpacingMinOp = ">=";
// Getter/Setter 省略
// 白名单校验:限制合法运算符,防止 SQL 注入
public void setZoneSpacingMinOp(String zoneSpacingMinOp) {
String[] validOps = {">", ">="};
this.zoneSpacingMinOp = Arrays.asList(validOps).contains(zoneSpacingMinOp)
? zoneSpacingMinOp : ">=";
}
public void setZoneSpacingMaxOp(String zoneSpacingMaxOp) {
String[] validOps = {"<", "<="};
this.zoneSpacingMaxOp = Arrays.asList(validOps).contains(zoneSpacingMaxOp)
? zoneSpacingMaxOp : "<=";
}
}
2. mapper.xml 动态拼接运算符
xml
<select id="getTrafficZoneFlow" resultMap="TrafficZoneInfoSpaceingResultMap">
select
zone_id,
target_zone_id,
zone_spacing,
project_plan_id
from
traffic_zone_spacing
<where>
1=1
<if test="zoneId != null">
and zone_id = #{zoneId}
</if>
<if test="targetZoneId != null">
and target_zone_id = #{targetZoneId}
</if>
<!-- 动态大于/大于等于:CDATA 包裹 ${zoneSpacingMinOp} -->
<if test="zoneSpacingMin != null">
and zone_spacing <![CDATA[${zoneSpacingMinOp}]]> #{zoneSpacingMin}
</if>
<!-- 动态小于/小于等于:CDATA 包裹 ${zoneSpacingMaxOp} -->
<if test="zoneSpacingMax != null">
and zone_spacing <![CDATA[${zoneSpacingMaxOp}]]> #{zoneSpacingMax}
</if>
</where>
</select>
四、总结
mapper.xml中不能直接写>=、<=,需用「<![CDATA[]]>包裹」或「XML 转义字符」。- 固定运算符场景优先选
<![CDATA[]]>,直观易维护。 - 需灵活切换运算符时,用
${}拼接+Java 白名单校验,兼顾灵活性和安全性。 - 核心避坑:运算符拼接用
${},数据传参用#{},特殊字符用<![CDATA[]]>包裹。