此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
JDBC 批处理作
如果对同一调用进行批处理,大多数 JDBC 驱动程序都会提供更高的性能 准备好的语句。通过将更新分组到批次中,可以限制往返次数 到数据库。
基本批处理作JdbcTemplate
你完成了JdbcTemplate
通过实现特殊接口的两种方法进行批处理,BatchPreparedStatementSetter
,并将该实现作为第二个参数传入
在你的batchUpdate
方法调用。您可以使用getBatchSize
方法提供
当前批次。您可以使用setValues
方法来设置参数的值
准备好的声明。调用此方法的次数getBatchSize
叫。以下示例更新t_actor
基于列表中条目的表,
并将整个列表用作批次:
-
Java
-
Kotlin
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 {
Actor actor = actors.get(i);
ps.setString(1, actor.getFirstName());
ps.setString(2, actor.getLastName());
ps.setLong(3, actor.getId().longValue());
}
public int getBatchSize() {
return actors.size();
}
});
}
// ... additional methods
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
object: BatchPreparedStatementSetter {
override fun setValues(ps: PreparedStatement, i: Int) {
ps.setString(1, actors[i].firstName)
ps.setString(2, actors[i].lastName)
ps.setLong(3, actors[i].id)
}
override fun getBatchSize() = actors.size
})
}
// ... additional methods
}
如果您处理更新流或从文件中读取,则可能会有
首选批次大小,但最后一个批次可能没有该数量的条目。在这个
case 中,您可以使用InterruptibleBatchPreparedStatementSetter
接口,这允许
一旦输入源用尽,您就会中断批处理。这isBatchExhausted
方法
允许您发出批次结束的信号。
具有对象列表的批处理作
两个JdbcTemplate
和NamedParameterJdbcTemplate
提供了另一种方式
提供批量更新。您无需实现特殊的批处理接口,而是
将调用中的所有参数值作为列表提供。框架循环这些
值,并使用内部准备好的语句 setter。API 因
是否使用命名参数。对于命名参数,请提供SqlParameterSource
,批处理的每个成员一个条目。您可以使用SqlParameterSourceUtils.createBatch
方便的方法来创建此数组,将
在 bean 样式对象数组中(具有与参数对应的 getter 方法),String
-键 控Map
实例(包含相应的参数作为值),或两者的混合。
以下示例显示了使用命名参数的批量更新:
-
Java
-
Kotlin
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));
}
// ... additional methods
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
return this.namedParameterJdbcTemplate.batchUpdate(
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
SqlParameterSourceUtils.createBatch(actors));
}
// ... additional methods
}
对于使用 classic 的 SQL 语句?
占位符,则传入列表
包含具有更新值的对象数组。此对象数组必须有一个条目
对于 SQL 语句中的每个占位符,并且它们的顺序必须与它们相同
在 SQL 语句中定义。
以下示例与前面的示例相同,只是它使用 classic
JDBC 公司?
占位符:
-
Java
-
Kotlin
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<>();
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);
}
// ... additional methods
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
val batch = mutableListOf<Array<Any>>()
for (actor in actors) {
batch.add(arrayOf(actor.firstName, actor.lastName, actor.id))
}
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?", batch)
}
// ... additional methods
}
我们之前描述的所有批量更新方法都会返回一个int
数组
包含每个批处理条目的受影响行数。此计数由
JDBC 驱动程序。如果计数不可用,则 JDBC 驱动程序将返回-2
.
在这种情况下,在基础上自动设置值 从 6.1.2 开始,Spring 绕过了默认的 或者,您可以考虑显式指定相应的 JDBC 类型,
要么通过 |
具有多个批次的批处理作
前面的批处理更新示例处理的批处理量太大,以至于您想要
将它们分成几个较小的批次。您可以使用以下方法来做到这一点
前面提到的,通过对batchUpdate
方法,但现在有一个
更方便的方法。除了 SQL 语句之外,此方法还采用Collection
包含参数的对象数,要对每个对象进行的更新次数
batch,以及一个ParameterizedPreparedStatementSetter
设置参数的值
准备好的声明。框架循环提供的值并中断
将调用更新为指定大小的批次。
以下示例显示了使用批大小 100 的批处理更新:
-
Java
-
Kotlin
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,
(PreparedStatement ps, Actor actor) -> {
ps.setString(1, actor.getFirstName());
ps.setString(2, actor.getLastName());
ps.setLong(3, actor.getId().longValue());
});
return updateCounts;
}
// ... additional methods
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): Array<IntArray> {
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
actors, 100) { ps, argument ->
ps.setString(1, argument.firstName)
ps.setString(2, argument.lastName)
ps.setLong(3, argument.id)
}
}
// ... additional methods
}
此调用的批量更新方法返回一个数组int
数组,其中包含
每个批次的数组条目,其中包含每次更新的受影响行数的数组。
顶级数组的长度表示运行的批次数,第二级
数组的长度表示该批次中的更新次数。中的更新次数
每个批次都应是为所有批次提供的批次大小(最后一个批次除外
这可能会更少),具体取决于提供的更新对象总数。更新
每个更新语句的计数是 JDBC 驱动程序报告的。如果计数为
不可用,则 JDBC 驱动程序返回-2
.