Spring框架也对JDBC进行了封装,它简化了JDBC操作,它是通过JdbcTemplate这个类来完成的。例如这个类的对象有一个batchUpdate()方法,可接收一个BatchPreparedStatementSetter的一个实现类实例。
1、JdbcTemplate的基本的批量操作
来看下面的代码:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[] batchUpdate(final List<Actor> actors) {
return this.jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, actors.get(i).getFirstName());
ps.setString(2, actors.get(i).getLastName());
ps.setLong(3, actors.get(i).getId().longValue());
}
public int getBatchSize() {
return actors.size();
}
});
}
}
这个DAO的实现类中有一个,batchUpdate方法,用于批量更新一个演员信息的数据库表,方法执行了this.jdbcTemplate.batchUpdate()
方法,而批量更新的关键是通过实现BatchPreparedStatementSetter
这个接口来完成的。被实现的setValues()
方法用于完成每次更新的操作,可多次被调用,getBatchSize()
方法某次批量更新的数目,即setValues()
方法调用的数次就是根据这个方法的返回值来决定的。
当然,JdbcTemplate
和NamedParameterJdbcTemplate
这两个类,都提供了另外一个执行批量操作的方法,这个方法它不用实现某个接口,而是直接把要批量更新的数据集合放到batchUpdate()
方法中就可以了,
A、含“?”占位符的语句
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[] batchUpdate(final List<Actor> actors) {
List<Object[]> batch = new ArrayList<Object[]>();
for (Actor actor : actors) {
Object[] values = new Object[] {
actor.getFirstName(), actor.getLastName(), actor.getId()};
batch.add(values);
}
return this.jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
batch);
}
}
这种方式的批量更新在生成相关的参数时,要我们把各个参数的与SQL语句的参数对应顺序处理好,其中batch
就是一个数组的数组,也就是说里面的每个子数组元素都存有相关的更新记录,子数组元素的顺序必须与SQL语句中参数的顺序一致。
B、含“锚点占位符”的语句
例如:
public class JdbcActorDao implements ActorDao {
private NamedParameterTemplate namedParameterJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public int[] batchUpdate(List<Actor> actors) {
return this.namedParameterJdbcTemplate.batchUpdate(
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
SqlParameterSourceUtils.createBatch(actors.toArray()));
}
}
在这个方法中,它的第二个参数接收了一个SqlParameterSource
类型的数组,这种形式的数组是通过SqlParameterSourceUtils.createBatch()
方法来生成的,个人觉得这种方法的优点是,只要我们把相关对象数组传进去就行,相关的参数对应顺序及设置不用我们处理。
2、处理大数目的批量操作
有一种情况是,当执行批量更新的执行数量比较大时,我们想把这个数目拆分成更小的数目来批量执行。当然我们可以重复执行上述提到的方法,这个也是可以的。但batchUpdate()
方法还有一个更简单的执行操作。来看下面的例子:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[][] batchUpdate(final Collection<Actor> actors) {
int[][] updateCounts = jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
actors,
100,
new ParameterizedPreparedStatementSetter<Actor>() {
public void setValues(PreparedStatement ps, Actor argument) throws SQLException {
ps.setString(1, argument.getFirstName());
ps.setString(2, argument.getLastName());
ps.setLong(3, argument.getId().longValue());
}
});
return updateCounts;
}
}
这个例子中,要求批量操作的总次数是100,但这里的batchUpdate()
方法自动帮我们把这个数目细化了,这个方法返回一个二维数组,其中这个数组中外层数组的长度就是代表本次细化的数目,里面的子数组的长度代表细化后每次要执行批量操作的次数,里面的数值代表每次操作中受影响的行数。