一、问题提出
众所周知,JDBC的批量操作接口(addBatch)不接受Select语句,也没有提供其它内建的接口。若想实现JDBC批量查询,不得不依靠自己想办法。
批量查询中最常见的查询条件是“=”判断,对此,通用方法是将WHERE子句中的“=”改为“IN (?, ?, ...)”。但这带来另一个问题,即绑定变量的数量不确定。
二、解决思路
通过度娘得知,很多帖子建议构造多个PreparedStatement,而它们的WHERE子句中包含数量不同的“?”,根据运行情况选择合适的PreparedStatement执行。
实话实说,此方法虽然可解决问题,但显得过于复杂,能不能用一个PreparedStatement就解决问题?
答案是可以,诀窍在于:IN 操作符的实际绑定值,既可以是重复的值,也可以是实际上不存在的值。
三、示例代码
以下是自己在实际项目中编写的代码:
List<Long> IDs = ...; // 查询用的ID队列 //每10个ID批量查询一次 PreparedStatement ps = conn.prepareStatement("SELECT * FROM MY_TABLE WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?))";
int index = 0; //ID的下标 int times = (IDs.size() - 1) / 10 + 1; //外循环次数 for (int i = 0; i < times; i++) { for (int j = 0; j < 10; j++) { // 如果不足10个(最后一次时)ID,以不可能的ID凑数 ps.setLong(j + 1, (index < IDs.size() ? IDs.get(index) : -j));
index ++; } rs = ps.executeQuery(); while (rs.next()) { ... //处理rs } }
因为实际上不会存在ID为负数的情况,所以本例中超出实际范围的绑定值设成了某个负数。
若不能确定某个值肯定不存在,则可用该批查询中的某个值(比如最后一个ID)多次绑定。代码修改很简单,这里省略。
四、进一步扩展
以上均是按“单一主键” 字段 + “等于判定”的形式讨论的,实际上在“组合主键”/"非主键"字段、“范围判定”/"like判定"/"常规表达式判定"的情况下,也一样可以使用,仅仅是绑定值略有差异而已。
对于更复杂的情况,还可以用OR操作符来实现,原理其实是一样的。限于篇幅,本文不再展开。