在 MyBatis 中,当使用#{a}占位符且参数a为null时,SQL 语句会变成:
WHERE a = null实际执行结果:不会有任何数据被查询出来,因为 SQL 中null = null的结果是unknown(相当于 false)。
详细说明
1.SQL 的 NULL 处理机制
在 SQL 中:
NULL表示"未知的值"或"缺失的值"任何与
NULL的比较(=、<>、<、>等)都返回NULL(逻辑假)即使
NULL = NULL也返回 NULL,而不是 true必须使用
IS NULL或IS NOT NULL来判断 NULL 值
2.MyBatis 示例
假设有以下映射:
<select id="findUsers" resultType="User"> SELECT * FROM users WHERE a = #{a} </select>当a为null时:
生成的 SQL:
WHERE a = null执行结果:返回空结果集(0行数据)
3.解决方案
方案1:动态 SQL(推荐)
<select id="findUsers" resultType="User"> SELECT * FROM users <where> <if test="a != null"> AND a = #{a} </if> <if test="a == null"> AND a IS NULL </if> </where> </select>方案2:使用<choose>
<select id="findUsers" resultType="User"> SELECT * FROM users WHERE <choose> <when test="a != null"> a = #{a} </when> <otherwise> a IS NULL </otherwise> </choose> </select>方案3:数据库函数(不推荐)
<select id="findUsers" resultType="User"> SELECT * FROM users WHERE IFNULL(a, '') = IFNULL(#{a}, '') </select>⚠️ 注意:这种方式有性能问题,且会干扰索引使用。
4.与${}的区别
<!-- 使用 #{},安全 --> WHERE a = #{a} → WHERE a = null <!-- 使用 ${},危险!SQL注入风险 --> WHERE a = ${a} → WHERE a = null两者结果相同,但${}是字符串替换,有 SQL 注入风险,不推荐使用。
5.最佳实践
使用 MyBatis 的动态 SQL 处理 NULL 值
在查询前先判断参数是否需要为 NULL
考虑使用默认值替代 NULL:
// Service 层处理 public List<User> findUsers(String a) { if (a == null) { a = ""; // 或使用其他默认值 } return userMapper.findUsers(a); }总结
WHERE a = #{a}当a为null时,查询不会报错,但返回空结果。这是因为 SQL 的逻辑特性决定的。实际开发中应该使用动态 SQL 来正确处理NULL值的查询。