MyBatis
一、直击痛点:那些年踩过的空字符串判断坑

我们先来看3个真实的生产故障案例,均来自鳄鱼java技术团队的用户支持记录:
案例1:某电商平台618大促期间,用户反馈输入空字符串搜索商品时返回空结果,而非预期的全量商品。经排查,XML中的判断逻辑为:
<if test="keyword != null and keyword != ''">
AND goods_name LIKE CONCAT('%', #{keyword}, '%')
</if>
当keyword是空字符串时,keyword != ''因OGNL类型匹配问题返回false,导致搜索条件未被拼接,加上SQL中默认的上架状态过滤条件,最终返回空列表。
案例2:某金融系统的转账功能,当用户输入空字符串作为备注时,触发数据库非空约束报错。原因是开发者写的默认值赋值逻辑从未生效:
<if test="remark == ''"> SET remark = '默认转账备注' </if>OGNL将单引号包裹的
''解析为char类型,与String类型的空字符串比较永远返回false,导致默认备注从未被设置。
案例3:某后台管理系统的用户查询功能,当管理员输入空字符串作为用户名查询时,返回所有用户而非预期的无结果。原因是开发者仅判断了null,未处理空字符串:
<if test="username != null">
AND user_name = #{username}
</if>
当username是空字符串时,条件生效并拼接AND user_name = '',导致查询出所有user_name为空的用户数据。
二、底层根源:OGNL表达式的隐性转换逻辑
要理解**MyBatis
1. 单引号与双引号的本质差异
OGNL中,单引号包裹的内容会被解析为Java的char类型,双引号包裹的内容会被解析为String类型。这意味着:
- '1'是一个char类型的字符'1';
- "1"是一个String类型的字符串"1";
当进行String == char比较时,Java的强类型校验会直接返回false,这是所有空字符串判断坑的核心根源。
2. 空字符串的特殊处理逻辑
当传入的参数是String类型的空字符串("")时,OGNL在解析name != ''时,会将空字符串与char类型的''进行比较。由于String的equals()方法会先判断参数类型是否为String,非String类型直接返回false,导致判断条件永远不生效。
3. null值的自动兼容机制
OGNL会自动处理null值,当参数为null时,name != null返回false,但不会抛出空指针异常。但如果忽略null判断直接执行字符串方法(如name.isEmpty()),仍会触发OGNL的空指针报错,这是需要注意的边界情况。
三、实战拆解:3种常见错误写法与正确方案
针对**MyBatis
错误写法1:单引号判断空字符串
<if test="name != null and name != ''">问题:空字符串与char类型比较返回false,导致条件不生效。 正确写法:双引号包裹空字符串或调用字符串方法
<if test='name != null and name != ""'> <if test="name != null and !name.trim().isEmpty()">
错误写法2:用==判断字符串值
<if test="status == '1'">问题:char类型的'1'与String类型的status比较永远返回false。 正确写法:双引号包裹字符串或调用equals方法
<if test='status == "1"'> <if test='"1".equals(status)'>
错误写法3:忽略null直接判断空字符串
<if test="name != ''">问题:当name为null时,OGNL返回false,虽不会报错但逻辑不严谨,易引发业务误解。 正确写法:同时判断null与空字符串
<if test='name != null and name != ""'>
四、源码溯源:MyBatis如何解析标签
为彻底搞清楚**MyBatis
1. **XML标签解析阶段**:XMLMapperBuilder解析SqlNode对象中,等待后续编译执行。
2. **表达式编译阶段**:当SqlSession执行SQL时,MyBatis通过OgnlCache将OGNL表达式编译为Expression对象。此时OGNL会进行词法分析,单引号内容被标记为CharLiteral,双引号内容被标记为StringLiteral。
3. **表达式执行阶段**:在SQL生成前,MyBatis将参数传入ExpressionContext执行表达式计算。当进行String与Char的比较时,OGNL调用String.equals(Character),而String的equals方法因参数类型不匹配直接返回false,最终导致判断逻辑不符合预期。
五、生产避坑:鳄鱼java独家优化方案
针对生产环境中频繁出现的**MyBatis
方案1:统一使用双引号规范表达式 在所有MyBatis XML中,字符串比较统一使用双引号包裹,彻底杜绝类型匹配问题。同时约定:所有空字符串判断必须包含null校验,示例:
<if test='keyword != null and keyword != "" and keyword.trim() != ""'>
AND goods_name LIKE CONCAT('%', #{keyword}, '%')
</if>
方案2:用bind标签统一参数预处理
通过
<bind name="validName" value='name == null ? "" : name.trim()' />
<if test='validName != ""'>
AND user_name = #{validName}
</if>
方案3:封装通用工具类集中判断 自定义字符串工具类,封装空值判断逻辑,在XML中通过OGNL调用,实现判断逻辑的集中管理:
// Java工具类
public class MyBatisStringUtils {
public static boolean isNotEmpty(String str) {
return str != null && !str 版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。





