对于跨表批量查询,我们可以采用“UNION”关键字,结合子查询还可以进行分页查询,但对于批量更新,JDBC无法对子查询视图进行更新,如下:
update
-- 子查询视图
(select * from t_security_menu ) as menu
set back_url = 'URL_2' where pk = 2
-- 提示如下错误:
-- [Err] 1288 - The target table menu of the UPDATE is not updatable
从上面的错误可以看出,JDBC批量更新必须在原表上进行,这又分为两种情况:
1. 在同一张表上进行批量更新;
2. 跨表进行批量更新;
这里以Spring JDBC的NamedParameterJdbcTemplate接口为例,依次对两种情况进行说明,其他类库用法与此类似。
1. 同表批量更新
在同一张表上进行批量更新,如果表名相同,而且响应的参数个数也相同,因此执行的SQL必然完全相同,只是参数不一致,这时候可以采用batchUpdate方法,如下:
// SQL语句含有两个参数
String sql = "update t_security_menu set back_url = :b1 where pk = :p1"
// 多个参数列表
Map<String, Object> param1 = ();
("b1", "URL_1");
("p1", 1L);
Map<String, Object> param2 = ();
("b1", "URL_2");
("p1", 2L);
// 创建参数列表
Map<String, Object>[] params = new Map[]{param1, param2};
// 执行SQL
int[] result = this.((), params);
从上面的代码可以看出,batchUpdate是将同一条语句执行多次,只是不断更换参数内容,所以缺点也很明显,只能在同一张表内。
2. 跨表进行批量更新
有时会碰到这样的情况,例如在按日期对表进行分布设计时,即每天的数据存储在一张单独的表内,所以需要跨表进行批量更新。
针对这种情况,首先,不能像例1一样,将表名作为参数,这样会出现转义错误(表名会加上单引号),所以必须单独处理每张表的SQL语句,如下:
StringBuilder builder = new StringBuilder();
// 一定要在语句末尾加上分号
("update t_security_menu set back_url = :b1 where pk = :p1;");
("update t_security_menu set back_url = :b2 where pk = :p2;");
// 把所有的参数放到一个Map对象内
Map<String, Object> param1 = ();
("b1", "URL_1");
("p1", 1L);
("b2", "URL_2");
("p2", 2L);
// 一定要调用execute方法
this.((), param1, new PreparedStatementCallback<Object>() {
@Override
public Object doInPreparedStatement(PreparedStatement args) throws SQLException, DataAccessException {
return null;
}
});
在上面的例子中,一定要注意两点,一是每条SQL语句的末尾一定要加上分号,二是一定要采用execute方法(batchUpdate方法出错)。
结论
批量插入、批量删除支持的语法都与更新类似,可以采用同样的解决办法,必须按表名对SQL语句进行整理。