PreparedStatement With IN Clause
预编译语句遇到 IN
PreparedStatement 又称为预编译语句,它在遇到 IN 语句的时候会产生一些违反直觉的地方,考虑下面的语句:
PreparedStatement ps = conn.prepareStatement(
"select * from users where id in (?)");
你可能希望 ps 有个 setList 或者 setArray 方法直接设置一个 list 或者数组,就像下面这样绑定参数:
List<String> ids = Arrays.asList("1", "2");
ps.setList(1, ids);
然而,这种写法并不能绑定 list 或者数组中的多个参数,因为上面的 sql 语句中只有一个占位符,只能绑定一个值,如果 list 中有三个元素,实际上你需要三个占位符。正确的写法应该是:
List<String> ids = Arrays.asList("1", "2");
String sql = String.format("select * from users where id in (%s)",
ids.stream().map(v -> "?").collect(Collectors.joining(", ")));
PreparedStatement ps = conn.prepareStatement(sql);
int index = 1;
for (Object id : ids) {
ps.setObject(index++, id);
}
Mybatis 中处理 IN
在 Mybatis 中,当你遇到 IN 语句的时候,同样的场景,我们一般这样写:
<select ...>
select * from users
WHERE id IN
<foreach item="id" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</select>
如果你打开了 Mybatis 的 sql 日志,你就会发现,Mybatis 使用的也是 PreparedStatement,同时生成的 sql 语句为:
select * from users where id in (?, ?)
结语
本文介绍了 PreparedStatement 遇到 IN 产生的问题和解决办法,这种方法可以有效的避免 sql 注入,然而也可能会带来一定的性能问题,有关性能问题的描述,感兴趣的读者可以参考 Batching Select Statements in JDBC。
有问题吗?点此反馈!
温馨提示:反馈需要登录