|
|
|
@ -160,8 +160,7 @@ strategy__. A transaction strategy is defined by the |
|
|
|
---- |
|
|
|
---- |
|
|
|
public interface PlatformTransactionManager { |
|
|
|
public interface PlatformTransactionManager { |
|
|
|
|
|
|
|
|
|
|
|
TransactionStatus getTransaction( |
|
|
|
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; |
|
|
|
TransactionDefinition definition) throws TransactionException; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void commit(TransactionStatus status) throws TransactionException; |
|
|
|
void commit(TransactionStatus status) throws TransactionException; |
|
|
|
|
|
|
|
|
|
|
|
@ -2990,10 +2989,10 @@ An `update()` convenience method supports the retrieval of primary keys generate |
|
|
|
database. This support is part of the JDBC 3.0 standard; see Chapter 13.6 of the |
|
|
|
database. This support is part of the JDBC 3.0 standard; see Chapter 13.6 of the |
|
|
|
specification for details. The method takes a `PreparedStatementCreator` as its first |
|
|
|
specification for details. The method takes a `PreparedStatementCreator` as its first |
|
|
|
argument, and this is the way the required insert statement is specified. The other |
|
|
|
argument, and this is the way the required insert statement is specified. The other |
|
|
|
argument is a `KeyHolder`, which contains the generated key on successful return from |
|
|
|
argument is a `KeyHolder`, which contains the generated key on successful return from the |
|
|
|
the update. There is not a standard single way to create an appropriate |
|
|
|
update. There is not a standard single way to create an appropriate `PreparedStatement` |
|
|
|
`PreparedStatement` (which explains why the method signature is the way it is). The |
|
|
|
(which explains why the method signature is the way it is). The following example works |
|
|
|
following example works on Oracle but may not work on other platforms: |
|
|
|
on Oracle but may not work on other platforms: |
|
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0] |
|
|
|
[source,java,indent=0] |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
@ -3244,6 +3243,7 @@ based on entries in a list. The entire list is used as the batch in this example |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
---- |
|
|
|
---- |
|
|
|
public class JdbcActorDao implements ActorDao { |
|
|
|
public class JdbcActorDao implements ActorDao { |
|
|
|
|
|
|
|
|
|
|
|
private JdbcTemplate jdbcTemplate; |
|
|
|
private JdbcTemplate jdbcTemplate; |
|
|
|
|
|
|
|
|
|
|
|
public void setDataSource(DataSource dataSource) { |
|
|
|
public void setDataSource(DataSource dataSource) { |
|
|
|
@ -3251,20 +3251,18 @@ based on entries in a list. The entire list is used as the batch in this example |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public int[] batchUpdate(final List<Actor> actors) { |
|
|
|
public int[] batchUpdate(final List<Actor> actors) { |
|
|
|
int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, " + |
|
|
|
return this.jdbcTemplate.batchUpdate( |
|
|
|
"last_name = ? where id = ?", |
|
|
|
"update t_actor set first_name = ?, last_name = ? where id = ?", |
|
|
|
new BatchPreparedStatementSetter() { |
|
|
|
new BatchPreparedStatementSetter() { |
|
|
|
public void setValues(PreparedStatement ps, int i) throws SQLException { |
|
|
|
public void setValues(PreparedStatement ps, int i) throws SQLException { |
|
|
|
ps.setString(1, actors.get(i).getFirstName()); |
|
|
|
ps.setString(1, actors.get(i).getFirstName()); |
|
|
|
ps.setString(2, actors.get(i).getLastName()); |
|
|
|
ps.setString(2, actors.get(i).getLastName()); |
|
|
|
ps.setLong(3, actors.get(i).getId().longValue()); |
|
|
|
ps.setLong(3, actors.get(i).getId().longValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public int getBatchSize() { |
|
|
|
public int getBatchSize() { |
|
|
|
return actors.size(); |
|
|
|
return actors.size(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
return updateCounts; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ... additional methods |
|
|
|
// ... additional methods |
|
|
|
@ -3287,8 +3285,9 @@ provide all parameter values in the call as a list. The framework loops over the |
|
|
|
values and uses an internal prepared statement setter. The API varies depending on |
|
|
|
values and uses an internal prepared statement setter. The API varies depending on |
|
|
|
whether you use named parameters. For the named parameters you provide an array of |
|
|
|
whether you use named parameters. For the named parameters you provide an array of |
|
|
|
`SqlParameterSource`, one entry for each member of the batch. You can use the |
|
|
|
`SqlParameterSource`, one entry for each member of the batch. You can use the |
|
|
|
`SqlParameterSource.createBatch` method to create this array, passing in either an array |
|
|
|
`SqlParameterSourceUtils.createBatch` convenience methods to create this array, passing |
|
|
|
of JavaBeans or an array of Maps containing the parameter values. |
|
|
|
in an array of bean-style objects (with getter methods corresponding to parameters) |
|
|
|
|
|
|
|
and/or String-keyed Maps (containing the corresponding parameters as values). |
|
|
|
|
|
|
|
|
|
|
|
This example shows a batch update using named parameters: |
|
|
|
This example shows a batch update using named parameters: |
|
|
|
|
|
|
|
|
|
|
|
@ -3296,18 +3295,17 @@ This example shows a batch update using named parameters: |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
[subs="verbatim,quotes"] |
|
|
|
---- |
|
|
|
---- |
|
|
|
public class JdbcActorDao implements ActorDao { |
|
|
|
public class JdbcActorDao implements ActorDao { |
|
|
|
|
|
|
|
|
|
|
|
private NamedParameterTemplate namedParameterJdbcTemplate; |
|
|
|
private NamedParameterTemplate namedParameterJdbcTemplate; |
|
|
|
|
|
|
|
|
|
|
|
public void setDataSource(DataSource dataSource) { |
|
|
|
public void setDataSource(DataSource dataSource) { |
|
|
|
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); |
|
|
|
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public int[] batchUpdate(final List<Actor> actors) { |
|
|
|
public int[] batchUpdate(List<Actor> actors) { |
|
|
|
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray()); |
|
|
|
return this.namedParameterJdbcTemplate.batchUpdate( |
|
|
|
int[] updateCounts = namedParameterJdbcTemplate.batchUpdate( |
|
|
|
|
|
|
|
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id", |
|
|
|
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id", |
|
|
|
batch); |
|
|
|
SqlParameterSourceUtils.createBatch(actors)); |
|
|
|
return updateCounts; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ... additional methods |
|
|
|
// ... additional methods |
|
|
|
@ -3336,15 +3334,12 @@ The same example using classic JDBC "?" placeholders: |
|
|
|
List<Object[]> batch = new ArrayList<Object[]>(); |
|
|
|
List<Object[]> batch = new ArrayList<Object[]>(); |
|
|
|
for (Actor actor : actors) { |
|
|
|
for (Actor actor : actors) { |
|
|
|
Object[] values = new Object[] { |
|
|
|
Object[] values = new Object[] { |
|
|
|
actor.getFirstName(), |
|
|
|
actor.getFirstName(), actor.getLastName(), actor.getId()}; |
|
|
|
actor.getLastName(), |
|
|
|
|
|
|
|
actor.getId()}; |
|
|
|
|
|
|
|
batch.add(values); |
|
|
|
batch.add(values); |
|
|
|
} |
|
|
|
} |
|
|
|
int[] updateCounts = jdbcTemplate.batchUpdate( |
|
|
|
return this.jdbcTemplate.batchUpdate( |
|
|
|
"update t_actor set first_name = ?, last_name = ? where id = ?", |
|
|
|
"update t_actor set first_name = ?, last_name = ? where id = ?", |
|
|
|
batch); |
|
|
|
batch); |
|
|
|
return updateCounts; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ... additional methods |
|
|
|
// ... additional methods |
|
|
|
@ -3355,6 +3350,24 @@ All of the above batch update methods return an int array containing the number |
|
|
|
affected rows for each batch entry. This count is reported by the JDBC driver. If the |
|
|
|
affected rows for each batch entry. This count is reported by the JDBC driver. If the |
|
|
|
count is not available, the JDBC driver returns a -2 value. |
|
|
|
count is not available, the JDBC driver returns a -2 value. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[NOTE] |
|
|
|
|
|
|
|
==== |
|
|
|
|
|
|
|
In such a scenario with automatic setting of values on an underlying `PreparedStatement`, |
|
|
|
|
|
|
|
the corresponding JDBC type for each value needs to be derived from the given Java type. |
|
|
|
|
|
|
|
While this usually works well, there is a potential for issues, e.g. with Map-contained |
|
|
|
|
|
|
|
`null` values: Spring will by default call `ParameterMetaData.getParameterType` in such a |
|
|
|
|
|
|
|
case which may be expensive with your JDBC driver. Please make sure to use a recent driver |
|
|
|
|
|
|
|
version, and consider setting the "spring.jdbc.getParameterType.ignore" property to "true" |
|
|
|
|
|
|
|
(as a JVM system property or in a `spring.properties` file in the root of your classpath) |
|
|
|
|
|
|
|
if you encounter a performance issue, e.g. as reported on Oracle 12c (SPR-16139). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alternatively, simply consider specifying the corresponding JDBC types explicitly: |
|
|
|
|
|
|
|
either via a 'BatchPreparedStatementSetter' as shown above, or via an explicit type |
|
|
|
|
|
|
|
array given to a 'List<Object[]>' based call, or via 'registerSqlType' calls on a |
|
|
|
|
|
|
|
custom 'MapSqlParameterSource' instance, or via a 'BeanPropertySqlParameterSource' |
|
|
|
|
|
|
|
which derives the SQL type from the Java-declared property type even for a null value. |
|
|
|
|
|
|
|
==== |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[jdbc-batch-multi]] |
|
|
|
[[jdbc-batch-multi]] |
|
|
|
==== Batch operations with multiple batches |
|
|
|
==== Batch operations with multiple batches |
|
|
|
|