此版本仍在开发中,尚未被视为稳定版本。最新的稳定版本请使用 Spring Framework 6.1.13! |
此版本仍在开发中,尚未被视为稳定版本。最新的稳定版本请使用 Spring Framework 6.1.13! |
如果对同一 JDBC 驱动程序进行批处理多个调用,则大多数 JDBC 驱动程序都会提供改进的性能 prepared 语句。通过将更新分组为批次,您可以限制往返次数 添加到数据库。
基本批量操作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,你可以使用 interface 来使用
一旦 input 源耗尽,您就会中断一个批处理。方法
用于向批处理结束发出信号。InterruptibleBatchPreparedStatementSetter
isBatchExhausted
使用对象列表进行批量操作
和 the 都提供了另一种方式
提供批处理更新。您无需实现特殊的批处理接口,而是
以列表形式提供调用中的所有参数值。框架在这些
值并使用内部准备好的语句 setter 进行设置。API 因
是否使用命名参数。对于命名参数,您需要为批处理的每个成员提供一个 , 一个条目。你可以使用便捷的方法创建这个数组,传递
在 Bean 样式对象数组中(具有与参数对应的 getter 方法)、-keyed 实例(包含相应的参数作为值)或两者的混合。JdbcTemplate
NamedParameterJdbcTemplate
SqlParameterSource
SqlParameterSourceUtils.createBatch
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
}
对于使用经典占位符的 SQL 语句,您需要传入一个列表
包含具有 Update 值的对象数组。此对象数组必须有一个条目
,并且它们的顺序必须与它们的顺序相同
在 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
}
我们之前介绍的所有批处理更新方法都返回一个数组
包含每个批处理条目受影响的行数。此计数由
JDBC 驱动程序。如果计数不可用,则 JDBC 驱动程序将返回值 。int
-2
在这种情况下,通过在底层 上自动设置值,
每个值的相应 JDBC 类型需要从给定的 Java 类型派生。
虽然这通常运行良好,但可能会出现问题(例如,使用
Map-contain-values 的值)。默认情况下,在这种情况下, Spring 会调用,这对于您的 JDBC 驱动程序来说可能会很昂贵。您应该使用最近的驱动程序
version 并考虑将属性设置为(作为 JVM 系统属性或通过 从 6.1.2 开始,Spring 绕过了 PostgreSQL 上的默认分辨率,并且
MS SQL 服务器。这是一种常见的优化,可避免进一步往返于 DBMS
对于已知对
特别是 PostgreSQL 和 MS SQL Server,特别是用于批处理操作。如果你
碰巧看到副作用,例如,在没有特定类型的情况下将字节数组设置为 null 时
指示,您可以显式设置
作为系统属性(见上文)来恢复完整分辨率。 或者,您可以考虑显式指定相应的 JDBC 类型。
要么通过 A(如前所述),要么通过显式
type 数组,通过对
自定义实例,通过 a 从 Java 声明的属性类型派生 SQL 类型(即使对于 null 值),或者
通过提供单个实例而不是纯 null 值。 |
在这种情况下,通过在底层 上自动设置值,
每个值的相应 JDBC 类型需要从给定的 Java 类型派生。
虽然这通常运行良好,但可能会出现问题(例如,使用
Map-contain-values 的值)。默认情况下,在这种情况下, Spring 会调用,这对于您的 JDBC 驱动程序来说可能会很昂贵。您应该使用最近的驱动程序
version 并考虑将属性设置为(作为 JVM 系统属性或通过 从 6.1.2 开始,Spring 绕过了 PostgreSQL 上的默认分辨率,并且
MS SQL 服务器。这是一种常见的优化,可避免进一步往返于 DBMS
对于已知对
特别是 PostgreSQL 和 MS SQL Server,特别是用于批处理操作。如果你
碰巧看到副作用,例如,在没有特定类型的情况下将字节数组设置为 null 时
指示,您可以显式设置
作为系统属性(见上文)来恢复完整分辨率。 或者,您可以考虑显式指定相应的 JDBC 类型。
要么通过 A(如前所述),要么通过显式
type 数组,通过对
自定义实例,通过 a 从 Java 声明的属性类型派生 SQL 类型(即使对于 null 值),或者
通过提供单个实例而不是纯 null 值。 |
具有多个批次的批量操作
前面的批处理更新示例处理的批处理非常大,以至于您希望
将它们分成几个较小的批次。您可以使用以下方法执行此操作
前面提到的,但现在有一个
更方便的方法。除了 SQL 语句之外,此方法还采用包含参数的对象,以及要为每个对象进行的更新次数
batch 和 a 设置参数的值
的 Script。框架会遍历提供的值并断开
将调用更新为指定大小的批处理。batchUpdate
Collection
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
}
此调用的 batch update 方法返回一个数组数组,其中包含一个
数组条目,其中包含每个更新受影响的行数的数组。
顶级数组的长度表示运行的批处理数,第二级
数组的长度表示该批次中的更新数量。中的更新数量
每个批次应为为所有批次提供的批次大小(最后一个批次除外)
这可能更少),具体取决于提供的 Update 对象总数。更新
count 是 JDBC 驱动程序报告的 count 语句。如果计数为
不可用,则 JDBC 驱动程序将返回值 。int
-2