情景:最近遇到了一个bug:
在DAO层里的这个sql语句,传入的参数没问题,在mysql里面查询也查询到了数据,为什么在dao层执行的时候查到数据不完整甚至没有呢?
主要原因:
Mybatis 在 处理#{}
时,#{}
传入参数是以字符串传 入 , 会将SQL 中的#{}
替 换 为 ?
号 , 调 用 PreparedStatement 的 set 方法来赋值。
Mybatis 在 处理${}
时是原值传入 ,就 是把{}
替换 成变量的 值,相当于 JDBC 中的 Statement 编译变量替换 后 ; #{}
对应的变量自动加上单引号 ‘’
; 变量替换后, ${}
对应 的变量不会加上单引号 ‘’。
也就是说,如果按#{}的话,传入的参数classIds为"210901,210900,210899,210898,210897",再加上单引号,我们只能使用到第一个参数!也就是变成了select in 210901
,而不是select in 210901,210900...
关于#{},${}:
where name in ('Jana','Tom');
我们可以在sql中直接写
name in ('Jana','Tom')
或者name in (${names})
(备注:String names = " ‘Jana’, ‘Tom’ ";
(使用$时会引起sql注入安全问题)
但是我们无法在sql中直接写name in (#{names});
会报参数个数错误,因为’Jana’,'Tom’会被解析成两个传参
String[] names={"Jana","Tom"};
解决方式
一, 使用${}
不过有注入风险
二,在select注解中。利用<foreach></foreach>
标签来遍历数组中的元素,在放入in()中。这个时候,我们传入的参数需要是List形式,而不是String。
要在@Select注解里面使用in查询需要有特定的语法和规则,有点类似XML的写法
@Select({"<script>"," select "," ah.id homeworkId, ah.homeworkTitle, ah.homeworkType, ah.grade, ah.createTime "," from hw_activityhomework_tab ah "," inner join hw_classhomework_tab ch on ah.id = ch.acthomeworkid "," where ch.classId in "," <foreach collection='classIds' item='classId' open='(' separator=',' close=')'> "," #{classId} "," </foreach> "," and ah.homeworkType in "," <foreach collection='typeStrs' item='typeStr' open='(' separator=',' close=')'> "," #{typeStr} "," </foreach> "," group by ah.id "," order by ah.homeworkType desc, ah.createTime desc "," </script>"})List<HomeworkAndScoreDTO> getOcHomeworkAndScore(@Param("classIds") String[] classIds, @Param("typeStrs")String[] typeStrs);
- 要有
<script>
标签 open='(' separator=','
中,‘(’ 和 separator中间要有空格,否则会报错
三,在xml中写(参考下面的图)