Mybatis中的in方法遇到的坑
一、 简介
在mapper.xml文件中使用**in (#{XXX})**查询出来的数据总是不正确,以此记录。
二,内容
在sql语句中使用in()进行查询结果很正常:
select * from sys_component where categoryid in (2,3,4)
在Mybatis中使用 in (#{XXX}) 就很有可能查询的结果会缺少:
//为了方便直接Controller调Mapper
public AjaxResult test(){
String categoryids="2,3,4";
return AjaxResult.success(sysComponentMapper.test(categoryids));
}
//Mapper
public interface SysComponentMapper {
List<SysComponent> test(String categoryids);
}
//Mapper.xml
<select id="test" resultType="com.zzsmart.dataflowapi.pojo.SysComponent">
select * from sys_component where categoryid in (#{categoryids})
</select>
查询出来的结果并不会报错,只有categoryid等于2的结果。原来Mybatis并不支持in (#{XXX}),但是支持in(${XXX}) 就能查询出正确的结果。
原因猜测
因为 # 传参方式和 $ 传参的方式不一样,# 传参会将语句进行预编译,然后再将内容赋值进去,而 $ 传参就是直接将参数拼接在语句后面直接编译。当 # 传参时,虽然内容被逗号分隔开,可能mybatis并不能进行识别,只能识别到第一位,所以查询出的结果不正确。(只是猜测,希望能够有大佬给出正确的解释)。
运用
都知道 $ 不能防止sql注入,不够安全,但是谁不想偷个懒呢?当参数不是由用户通过前端传过来的,而是后端自己生成的,$还是可以用一用的。
但是最好的写法还是使用foreach:
//controller层
public AjaxResult test(){
List<Integer> categoryids=new ArrayList<>();
categoryids.add(2);
categoryids.add(3);
categoryids.add(4);
return AjaxResult.success(sysComponentMapper.test(categoryids));
}
//mapper层
public interface SysComponentMapper {
List<SysComponent> test(@Param("categoryids") List<Integer> categoryids);
}
//mapper.xml
<select id="test" resultType="com.zzsmart.dataflowapi.pojo.SysComponent">
select * from sys_component
where
categoryid in
<foreach collection="categoryids" item="cid" open="(" close=")" separator=",">
#{cid}
</foreach>
</select>