在 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值的查询。