场景介绍
我的场景如下

用户可以根据前置课程,编程语言以及相关技术三个字段,以及是否只显示收藏来筛选论文。
且支持搜索功能。
这时候经常出现一个问题。
当搜索框输入内容且搜索时,功能一切正常。
但是当搜索框没有内容的时候,功能出现问题。
给大家看一下我的后端代码
XML
<select id="selectByFilter" resultMap="PaperResultMap">
select distinct p.*, t.name as teacherName, t.address as teacherAddress,
t.phone as teacherPhone, t.wechat as teacherWechat, t.qq as teacherQQ, t.email as teacherEmail,
t.research_direction as teacherResearchDirection, t.avatar as teacherAvatar
from `paper` p
left join `paper-sys`.paper_course pc on p.id = pc.paper_id
left join `paper-sys`.paper_language pl on p.id = pl.paper_id
left join `paper-sys`.paper_technology pt on p.id = pt.paper_id
left join `paper-sys`.teacher t on p.teacher_id = t.id
<where>
<if test="studentId != null">
and p.id in (
select paper_id from `collect` where student_id = #{studentId}
)
</if>
<if test="courseIds != null and courseIds.size() > 0">
and pc.course_id IN
<foreach collection="courseIds" item="item" open="(" close=")" separator=",">#{item}</foreach>
</if>
<if test="languageIds != null and languageIds.size() > 0">
and pl.language_id IN
<foreach collection="languageIds" item="item" open="(" close=")" separator=",">#{item}</foreach>
</if>
<if test="technologyIds != null and technologyIds.size() > 0">
and pl.language_id IN
<foreach collection="technologyIds" item="item" open="(" close=")" separator=",">#{item}</foreach>
</if>
<if test="keyword != null">
and t.name like concat('%', #{keyword},'%') or p.name like concat('%', #{keyword} , '%')
</if>
<if test="id != null">
and p.id = #{id}
</if>
</where>
</select>
问题分析
我想问题一定出在sql语句上面。
所以我试了一下把sql语句代入后,在数据库直接查询会出现什么结果。
这时候就看出来问题了。
去掉那些if标签的test时是这样
java
WHERE (p.id in ( select paper_id from `collect` where student_id = ? ) and t.name like concat('%', ?,'%')) or p.name like concat('%', ? , '%')
在 SQL 里,AND
运算符的优先级高于 OR
运算符。
那么其实我的代码实际执行逻辑和我想象的是不一样的。
这就意味着,只要论文名称(p.name
)符合关键字条件,无论 p.id
是否在指定学生收藏的论文 ID 列表里,该论文都会被查询出来,从而导致筛选 studentId
的条件失效。
解决方案
解决方案就非常简单了
只需要给扩上括号就好了。

所以大家在使用and和or的时候一定要注意。
否则可能会发生难以察觉的bug