JDBC批处理更新
JDBC批处理更新是将一批更新分组在一起,并成批发送到数据库,而不是一个接一个地发送。
一次性将一批更新发送到数据库要比逐个发送更新(等待每个更新完成)要快。发送一批更新(仅一次往返)所涉及的网络流量较少,并且数据库可能能够并行执行某些更新。与逐个执行更新相比,速度可能会很大。
我们可以批处理SQL插入,更新和删除。批量选择语句没有意义。
有两种执行JDBC批处理更新的方法:
- 使用语句 Statement
- 使用预声明语句 PreparedStatement
本JDBC批处理更新教程在以下各节中介绍了这两种方法。
语句批处理更新
我们可以使用Statement对象执行批量更新。我们可以使用addBatch()和executeBatch()方法来实现。这是一个例子:
Statement statement = null;
try{
statement = connection.createStatement();
statement.addBatch("update people set firstname='John' where id=123");
statement.addBatch("update people set firstname='Eric' where id=456");
statement.addBatch("update people set firstname='May' where id=789");
int[] recordsAffected = statement.executeBatch();
} finally {
if(statement != null) statement.close();
}
首先,使用addBatch()方法添加要在批处理中执行的SQL语句。
然后,我们使用executeBatch()执行SQL语句。 " executeBatch()"方法返回的" int []"数组是一个" int"数组,用于告诉该批处理中的每个已执行SQL语句影响了多少条记录。
PreparedStatement批处理更新
我们也可以使用PreparedStatement对象执行批量更新。 " PreparedStatement"使我们可以重复使用相同的SQL语句,并只需其中插入新参数,即可执行每次更新。这是一个例子:
String sql = "update people set firstname=? , lastname=? where id=?";
PreparedStatement preparedStatement = null;
try{
preparedStatement =
connection.prepareStatement(sql);
preparedStatement.setString(1, "Gary");
preparedStatement.setString(2, "Larson");
preparedStatement.setLong (3, 123);
preparedStatement.addBatch();
preparedStatement.setString(1, "Stan");
preparedStatement.setString(2, "Lee");
preparedStatement.setLong (3, 456);
preparedStatement.addBatch();
int[] affectedRecords = preparedStatement.executeBatch();
}finally {
if(preparedStatement != null) {
preparedStatement.close();
}
}
首先,从带有问号的SQL语句创建一个" PreparedStatement",以显示将参数值插入SQL的位置。
其次,将每组参数值插入prepareStatement中,并调用addBatch()方法。这会将参数值内部添加到批处理中。现在,我们可以添加另一组值,以将其插入到SQL语句中。将完整的批处理发送到数据库后,每组参数都将插入到SQL中并分别执行。
第三,调用executeBatch()方法,该方法执行所有批处理更新。 SQL语句和参数集将一次性发送到数据库。 " executeBatch()"方法返回的" int []"数组是一个" int"数组,用于告诉该批处理中的每个已执行SQL语句影响了多少条记录。
循环添加批处理
通常,我们会从for循环或者while循环内部将批处理添加到Statement或者PreparedStatement中。循环中的每次迭代都会添加一批。这是从for循环内部将批次添加到PreparedStatement的示例:
List<Person> persons = ... // get a list of Person objects from somewhere.
String sql = "update people set firstname=? , lastname=? where id=?";
PreparedStatement preparedStatement = null;
try{
preparedStatement =
connection.prepareStatement(sql);
for(Person person : persons) {
preparedStatement.setString(1, person.getFirstName());
preparedStatement.setString(2, person.getLastName());
preparedStatement.setLong (3, person.getId());
preparedStatement.addBatch();
}
int[] affectedRecords = preparedStatement.executeBatch();
}finally {
if(preparedStatement != null) {
preparedStatement.close();
}
}
在上面的示例中,我们从某处获得了" Person"对象的列表。本部分未包括在示例中,因为该列表的来源与其无关。重要的是如何迭代列表,并将每个" Person"对象中的值添加到批处理中。将所有" Person"对象添加到批次后,将执行批次更新。
顺便说一下,假设使用的Person类看起来像这样:
public class Person{
private String firstName = null;
private String lastName = null;
private long id = -1;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
}
批量更新和事务
重要的是要记住,添加到Statement或者PreparedStatement的每个更新都是由数据库单独执行的。这意味着,其中一些可能其中之一失败之前就已经成功。现在,所有成功的语句都将应用于数据库,但其余更新可能未应用。这可能导致数据库中的数据不一致。
为避免这种情况,我们可以在JDBC事务中执行批处理更新。在事务内部执行时,我们可以确保执行所有更新或者不执行任何更新。万一其中一个更新失败,任何成功的更新都可以回滚。

