Added batchUpdate method taking a Collection, a batch size and a ParameterizedPreparedStatementSetter as arguments (SPR-6334)
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.jdbc.core;
|
package org.springframework.jdbc.core;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -1005,6 +1006,18 @@ public interface JdbcOperations {
|
|||||||
*/
|
*/
|
||||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes);
|
public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute multiple batches using the supplied SQL statement with the collect of supplied arguments.
|
||||||
|
* The arguments' values will be set using the ParameterizedPreparedStatementSetter.
|
||||||
|
* Each batch should be of size indicated in 'batchSize'.
|
||||||
|
* @param sql the SQL statement to execute.
|
||||||
|
* @param batchArgs the List of Object arrays containing the batch of arguments for the query
|
||||||
|
* @param argTypes SQL types of the arguments
|
||||||
|
* (constants from <code>java.sql.Types</code>)
|
||||||
|
* @return an array containing for each batch another array containing the numbers of rows affected
|
||||||
|
* by each update in the batch
|
||||||
|
*/
|
||||||
|
public <T> int[][] batchUpdate(String sql, Collection<T> batchArgs, int batchSize, ParameterizedPreparedStatementSetter<T> pss);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Methods dealing with callable statements
|
// Methods dealing with callable statements
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.sql.SQLException;
|
|||||||
import java.sql.SQLWarning;
|
import java.sql.SQLWarning;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -930,6 +931,58 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
|||||||
return BatchUpdateUtils.executeBatchUpdate(sql, batchArgs, argTypes, this);
|
return BatchUpdateUtils.executeBatchUpdate(sql, batchArgs, argTypes, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.jdbc.core.JdbcOperations#batchUpdate(java.lang.String, java.util.Collection, int, org.springframework.jdbc.core.ParameterizedPreparedStatementSetter)
|
||||||
|
*
|
||||||
|
* Contribution by Nicolas Fabre
|
||||||
|
*/
|
||||||
|
public <T> int[][] batchUpdate(String sql, final Collection<T> batchArgs, final int batchSize, final ParameterizedPreparedStatementSetter<T> pss) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Executing SQL batch update [" + sql + "] with a batch size of " + batchSize);
|
||||||
|
}
|
||||||
|
return execute(sql, new PreparedStatementCallback<int[][]>() {
|
||||||
|
public int[][] doInPreparedStatement(PreparedStatement ps) throws SQLException {
|
||||||
|
List<int[]> rowsAffected = new ArrayList<int[]>();
|
||||||
|
try {
|
||||||
|
boolean batchSupported = true;
|
||||||
|
if (!JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||||
|
batchSupported = false;
|
||||||
|
logger.warn("JDBC Driver does not support Batch updates; resorting to single statement execution");
|
||||||
|
}
|
||||||
|
int n = 0;
|
||||||
|
for (T obj : batchArgs) {
|
||||||
|
pss.setValues(ps, obj);
|
||||||
|
n++;
|
||||||
|
if (batchSupported) {
|
||||||
|
ps.addBatch();
|
||||||
|
if (n % batchSize == 0 || n == batchArgs.size()) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
int batchIdx = (n % batchSize == 0) ? n / batchSize : (n / batchSize) + 1;
|
||||||
|
int items = n - ((n % batchSize == 0) ? n / batchSize - 1 : (n / batchSize)) * batchSize;
|
||||||
|
logger.debug("Sending SQL batch update #" + batchIdx + " with " + items + " items");
|
||||||
|
}
|
||||||
|
rowsAffected.add(ps.executeBatch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i = ps.executeUpdate();
|
||||||
|
rowsAffected.add(new int[] {i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[][] result = new int[rowsAffected.size()][];
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = rowsAffected.get(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
if (pss instanceof ParameterDisposer) {
|
||||||
|
((ParameterDisposer) pss).cleanupParameters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Methods dealing with callable statements
|
// Methods dealing with callable statements
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2011 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.jdbc.core;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameterized callback interface used by the {@link JdbcTemplate} class for batch updates.
|
||||||
|
*
|
||||||
|
* <p>This interface sets values on a {@link java.sql.PreparedStatement} provided
|
||||||
|
* by the JdbcTemplate class, for each of a number of updates in a batch using the
|
||||||
|
* same SQL. Implementations are responsible for setting any necessary parameters.
|
||||||
|
* SQL with placeholders will already have been supplied.
|
||||||
|
*
|
||||||
|
* <p>Implementations <i>do not</i> need to concern themselves with SQLExceptions
|
||||||
|
* that may be thrown from operations they attempt. The JdbcTemplate class will
|
||||||
|
* catch and handle SQLExceptions appropriately.
|
||||||
|
*
|
||||||
|
* @author Nicolas Fabre
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @since 3.1
|
||||||
|
* @see JdbcTemplate#batchUpdate(String sql, Collection<T> objs, int batchSize, ParameterizedPreparedStatementSetter<T> pss)
|
||||||
|
*/
|
||||||
|
public interface ParameterizedPreparedStatementSetter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set parameter values on the given PreparedStatement.
|
||||||
|
*
|
||||||
|
* @param ps the PreparedStatement to invoke setter methods on
|
||||||
|
* @param argument the object containing the values to be set
|
||||||
|
* @throws SQLException if a SQLException is encountered (i.e. there is no need to catch SQLException)
|
||||||
|
*/
|
||||||
|
void setValues(PreparedStatement ps, T argument) throws SQLException;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import java.sql.SQLWarning;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -1189,6 +1190,76 @@ public class JdbcTemplateTests extends AbstractJdbcTests {
|
|||||||
BatchUpdateTestHelper.verifyBatchUpdateMocks(ctrlPreparedStatement, ctrlDatabaseMetaData);
|
BatchUpdateTestHelper.verifyBatchUpdateMocks(ctrlPreparedStatement, ctrlDatabaseMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBatchUpdateWithCollectionOfObjects() throws Exception {
|
||||||
|
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
|
||||||
|
final List<Integer> ids = new ArrayList<Integer>();
|
||||||
|
ids.add(Integer.valueOf(100));
|
||||||
|
ids.add(Integer.valueOf(200));
|
||||||
|
ids.add(Integer.valueOf(300));
|
||||||
|
final int[] rowsAffected1 = new int[] { 1, 2 };
|
||||||
|
final int[] rowsAffected2 = new int[] { 3 };
|
||||||
|
|
||||||
|
MockControl ctrlPreparedStatement = MockControl.createControl(PreparedStatement.class);
|
||||||
|
PreparedStatement mockPreparedStatement = (PreparedStatement) ctrlPreparedStatement.getMock();
|
||||||
|
mockPreparedStatement.getConnection();
|
||||||
|
ctrlPreparedStatement.setReturnValue(mockConnection);
|
||||||
|
mockPreparedStatement.setInt(1, ids.get(0));
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.addBatch();
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.setInt(1, ids.get(1));
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.addBatch();
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.setInt(1, ids.get(2));
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.executeBatch();
|
||||||
|
ctrlPreparedStatement.setReturnValue(rowsAffected1);
|
||||||
|
mockPreparedStatement.addBatch();
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
mockPreparedStatement.executeBatch();
|
||||||
|
ctrlPreparedStatement.setReturnValue(rowsAffected2);
|
||||||
|
if (debugEnabled) {
|
||||||
|
mockPreparedStatement.getWarnings();
|
||||||
|
ctrlPreparedStatement.setReturnValue(null);
|
||||||
|
}
|
||||||
|
mockPreparedStatement.close();
|
||||||
|
ctrlPreparedStatement.setVoidCallable();
|
||||||
|
|
||||||
|
MockControl ctrlDatabaseMetaData = MockControl.createControl(DatabaseMetaData.class);
|
||||||
|
DatabaseMetaData mockDatabaseMetaData = (DatabaseMetaData) ctrlDatabaseMetaData.getMock();
|
||||||
|
mockDatabaseMetaData.getDatabaseProductName();
|
||||||
|
ctrlDatabaseMetaData.setReturnValue("MySQL");
|
||||||
|
mockDatabaseMetaData.supportsBatchUpdates();
|
||||||
|
ctrlDatabaseMetaData.setReturnValue(true);
|
||||||
|
|
||||||
|
mockConnection.prepareStatement(sql);
|
||||||
|
ctrlConnection.setReturnValue(mockPreparedStatement);
|
||||||
|
mockConnection.getMetaData();
|
||||||
|
ctrlConnection.setReturnValue(mockDatabaseMetaData, 2);
|
||||||
|
|
||||||
|
ctrlPreparedStatement.replay();
|
||||||
|
ctrlDatabaseMetaData.replay();
|
||||||
|
replay();
|
||||||
|
|
||||||
|
ParameterizedPreparedStatementSetter setter = new ParameterizedPreparedStatementSetter<Integer>() {
|
||||||
|
public void setValues(PreparedStatement ps, Integer argument) throws SQLException {
|
||||||
|
ps.setInt(1, argument.intValue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JdbcTemplate template = new JdbcTemplate(mockDataSource, false);
|
||||||
|
|
||||||
|
int[][] actualRowsAffected = template.batchUpdate(sql, ids, 2, setter);
|
||||||
|
assertTrue("executed 2 updates", actualRowsAffected[0].length == 2);
|
||||||
|
assertEquals(rowsAffected1[0], actualRowsAffected[0][0]);
|
||||||
|
assertEquals(rowsAffected1[1], actualRowsAffected[0][1]);
|
||||||
|
assertEquals(rowsAffected2[0], actualRowsAffected[1][0]);
|
||||||
|
|
||||||
|
ctrlPreparedStatement.verify();
|
||||||
|
ctrlDatabaseMetaData.verify();
|
||||||
|
}
|
||||||
|
|
||||||
public void testCouldntGetConnectionOrExceptionTranslator() throws SQLException {
|
public void testCouldntGetConnectionOrExceptionTranslator() throws SQLException {
|
||||||
SQLException sex = new SQLException("foo", "07xxx");
|
SQLException sex = new SQLException("foo", "07xxx");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||||
<chapter id="jdbc">
|
<chapter id="jdbc">
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
<title>Introduction to Spring Framework JDBC</title>
|
<title>Introduction to Spring Framework JDBC</title>
|
||||||
|
|
||||||
<para>The value-add provided by the Spring Framework JDBC abstraction is
|
<para>The value-add provided by the Spring Framework JDBC abstraction is
|
||||||
perhaps best shown by the sequence of actions outlined in the table
|
perhaps best shown by the sequence of actions outlined in the table below.
|
||||||
below. The table shows what actions Spring will take care of and which
|
The table shows what actions Spring will take care of and which actions
|
||||||
actions are the responsibility of you, the application developer.<!--Is this sequence correct, as far as what developer does and doesn't do? Does it adhere to info in the rest of the chapter?
|
are the responsibility of you, the application developer.<!--Is this sequence correct, as far as what developer does and doesn't do? Does it adhere to info in the rest of the chapter?
|
||||||
--><!--How does JDBC know what connection parameters are if a human does not at some point define them?--><!--TR: OK. I have rewritten this as a table indicating who has what responsibility. --></para>
|
--><!--How does JDBC know what connection parameters are if a human does not at some point define them?--><!--TR: OK. I have rewritten this as a table indicating who has what responsibility. --></para>
|
||||||
|
|
||||||
<table align="left" width="">
|
<table align="left" width="">
|
||||||
@@ -1036,7 +1036,8 @@ public class ExecuteAnUpdate {
|
|||||||
<section id="jdbc-auto-genereted-keys">
|
<section id="jdbc-auto-genereted-keys">
|
||||||
<title>Retrieving auto-generated keys</title>
|
<title>Retrieving auto-generated keys</title>
|
||||||
|
|
||||||
<para>An <methodname>update()</methodname> convenience method supports<!--Give name of this method. Also indicate *what* is acquiring the primary keys. TR: Changed to *retrieval*.
|
<para>An <methodname>update()</methodname> convenience method
|
||||||
|
supports<!--Give name of this method. Also indicate *what* is acquiring the primary keys. TR: Changed to *retrieval*.
|
||||||
The name of the method is *update*.--> the retrieval of primary keys generated
|
The name of the method is *update*.--> the retrieval of primary keys generated
|
||||||
by the database. This support is part of the JDBC 3.0 standard; see
|
by 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
|
Chapter 13.6 of the specification for details. The method takes a
|
||||||
@@ -1368,7 +1369,7 @@ dataSource.setPassword("");</programlisting>
|
|||||||
<classname>SimpleJdbcTemplate</classname>.</para>
|
<classname>SimpleJdbcTemplate</classname>.</para>
|
||||||
|
|
||||||
<section id="jdbc-advanced-classic">
|
<section id="jdbc-advanced-classic">
|
||||||
<title>Batch operations with the JdbcTemplate</title>
|
<title>Basic batch operations with the JdbcTemplate</title>
|
||||||
|
|
||||||
<para>You accomplish <classname>JdbcTemplate</classname> batch
|
<para>You accomplish <classname>JdbcTemplate</classname> batch
|
||||||
processing by implementing two methods of a special interface,
|
processing by implementing two methods of a special interface,
|
||||||
@@ -1418,11 +1419,12 @@ dataSource.setPassword("");</programlisting>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="jdbc-advanced-simple">
|
<section id="jdbc-advanced-simple">
|
||||||
<title>Batch operations with the SimpleJdbcTemplate</title>
|
<title>Batch operations with a List of objects</title>
|
||||||
|
|
||||||
<para>The <classname>SimpleJdbcTemplate</classname> provides an
|
<para>Both the <classname>JdbcTemplate</classname> and the
|
||||||
alternate way of providing the batch update. Instead of implementing a
|
<classname>NamedParameterJdbcTemplate</classname> provides an alternate
|
||||||
special batch interface, you provide all parameter values in the call.
|
way of providing the batch update. Instead of implementing a special
|
||||||
|
batch interface, you provide all parameter values in the call as a list.
|
||||||
The framework loops over these values and uses an internal prepared
|
The framework loops over these values and uses an internal prepared
|
||||||
statement setter. The API varies depending on whether you use named
|
statement setter. The API varies depending on whether you use named
|
||||||
parameters. For the named parameters you provide an array of
|
parameters. For the named parameters you provide an array of
|
||||||
@@ -1435,15 +1437,15 @@ dataSource.setPassword("");</programlisting>
|
|||||||
<para>This example shows a batch update using named parameters:</para>
|
<para>This example shows a batch update using named parameters:</para>
|
||||||
|
|
||||||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
private NamedParameterTemplate namedParameterJdbcTemplate;
|
||||||
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
public void setDataSource(DataSource dataSource) {
|
||||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] batchUpdate(final List<Actor> actors) {
|
public int[] batchUpdate(final List<Actor> actors) {
|
||||||
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());
|
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());
|
||||||
int[] updateCounts = simpleJdbcTemplate.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);
|
batch);
|
||||||
return updateCounts;
|
return updateCounts;
|
||||||
@@ -1459,10 +1461,10 @@ dataSource.setPassword("");</programlisting>
|
|||||||
<para>The same example using classic JDBC "?" placeholders:</para>
|
<para>The same example using classic JDBC "?" placeholders:</para>
|
||||||
|
|
||||||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
public void setDataSource(DataSource dataSource) {
|
public void setDataSource(DataSource dataSource) {
|
||||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] batchUpdate(final List<Actor> actors) {
|
public int[] batchUpdate(final List<Actor> actors) {
|
||||||
@@ -1474,17 +1476,79 @@ dataSource.setPassword("");</programlisting>
|
|||||||
actor.getId()};
|
actor.getId()};
|
||||||
batch.add(values);
|
batch.add(values);
|
||||||
}
|
}
|
||||||
int[] updateCounts = simpleJdbcTemplate.batchUpdate(
|
int[] updateCounts = 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;
|
return updateCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... additional methods
|
// ... additional methods
|
||||||
}</programlisting>All batch update methods return an int array containing the
|
}</programlisting>All of the above batch update methods return an int array
|
||||||
number of affected rows for each batch entry. This count is reported by
|
containing the number of affected rows for each batch entry. This count
|
||||||
the JDBC driver. If the count is not available, the JDBC driver returns
|
is reported by the JDBC driver. If the count is not available, the JDBC
|
||||||
a -2 value.</para>
|
driver returns a -2 value.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="jdbc-advanced-simple">
|
||||||
|
<title>Batch operations with multiple batches</title>
|
||||||
|
|
||||||
|
<para>The last example of a batch update deals with batches that are so
|
||||||
|
large that you want to break them up into several smaller batches. You
|
||||||
|
can of course do this with the methods mentioned above by making
|
||||||
|
multiple calls to the <classname>batchUpdate</classname> method, but
|
||||||
|
there is now a more convenient method. This method takes, in addition to
|
||||||
|
the SQL statement, a Collection of objects containing the parameters,
|
||||||
|
the number of updates to make for each batch and a
|
||||||
|
<classname>ParameterizedPreparedStatementSetter</classname> to set the
|
||||||
|
values for the parameters of the prepared statement. The framework loops
|
||||||
|
over the provided values and breaks the update calls into batches of the
|
||||||
|
size specified. </para>
|
||||||
|
|
||||||
|
<para>This example shows a batch update using a batch size of
|
||||||
|
100:</para>
|
||||||
|
|
||||||
|
<para><programlisting language="java">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) {
|
||||||
|
Collection<Object[]> batch = new ArrayList<Object[]>();
|
||||||
|
for (Actor actor : actors) {
|
||||||
|
Object[] values = new Object[] {
|
||||||
|
actor.getFirstName(),
|
||||||
|
actor.getLastName(),
|
||||||
|
actor.getId()};
|
||||||
|
batch.add(values);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... additional methods
|
||||||
|
}</programlisting>The batch update methods for this call returns an array of
|
||||||
|
int arrays containing an array entry for each batch with an array of the
|
||||||
|
number of affected rows for each update. The top level array's length
|
||||||
|
indicates the number of batches executed and the second level array's
|
||||||
|
length indicates the number of updates in that batch. The number of
|
||||||
|
updates in each batch should be the the batch size provided for all
|
||||||
|
batches except for the last one that might be less, depending on the
|
||||||
|
total number of updat objects provided. The update count for each update
|
||||||
|
stament is the one reported by the JDBC driver. If the count is not
|
||||||
|
available, the JDBC driver returns a -2 value.</para>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -1715,9 +1779,9 @@ END;</programlisting>The <code>in_id</code> parameter contains the
|
|||||||
<para>The <classname>SimpleJdbcCall</classname> is declared in a similar
|
<para>The <classname>SimpleJdbcCall</classname> is declared in a similar
|
||||||
manner to the <classname>SimpleJdbcInsert</classname>. You should
|
manner to the <classname>SimpleJdbcInsert</classname>. You should
|
||||||
instantiate and configure the class in the initialization method of your
|
instantiate and configure the class in the initialization method of your
|
||||||
data access layer. Compared to the StoredProcedure class, you don't
|
data access layer. Compared to the StoredProcedure class, you don't have
|
||||||
have to create a subclass and you don't have to declare parameters that
|
to create a subclass and you don't have to declare parameters that can
|
||||||
can be looked up in the database metadata. <!--Reword preceding: You need not subclass *what?* and you declare *what* in init method? TR: Revised, pplease review.-->Following
|
be looked up in the database metadata. <!--Reword preceding: You need not subclass *what?* and you declare *what* in init method? TR: Revised, pplease review.-->Following
|
||||||
is an example of a SimpleJdbcCall configuration using the above stored
|
is an example of a SimpleJdbcCall configuration using the above stored
|
||||||
procedure. The only configuration option, in addition to the
|
procedure. The only configuration option, in addition to the
|
||||||
<classname>DataSource</classname>, is the name of the stored
|
<classname>DataSource</classname>, is the name of the stored
|
||||||
@@ -2651,9 +2715,9 @@ clobReader.close();</programlisting>
|
|||||||
<para>In addition to the primitive values in the value list, you can
|
<para>In addition to the primitive values in the value list, you can
|
||||||
create a <classname>java.util.List</classname> of object arrays. This
|
create a <classname>java.util.List</classname> of object arrays. This
|
||||||
list would support multiple expressions defined for the <code>in</code>
|
list would support multiple expressions defined for the <code>in</code>
|
||||||
clause such as <code>select * from T_ACTOR where (id, last_name) in
|
clause such as <code>select * from T_ACTOR where (id, last_name) in ((1,
|
||||||
((1, 'Johnson'), (2, 'Harrop'))</code>. This
|
'Johnson'), (2, 'Harrop'))</code>. This of course requires that your
|
||||||
of course requires that your database supports this syntax.</para>
|
database supports this syntax.</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="jdbc-complex-types">
|
<section id="jdbc-complex-types">
|
||||||
@@ -2920,8 +2984,7 @@ public class DataAccessUnitTestTemplate {
|
|||||||
existing data, the XML namespace provides a couple more options. The
|
existing data, the XML namespace provides a couple more options. The
|
||||||
first is flag to switch the initialization on and off. This can be set
|
first is flag to switch the initialization on and off. This can be set
|
||||||
according to the environment (e.g. to pull a boolean value from system
|
according to the environment (e.g. to pull a boolean value from system
|
||||||
properties or an environment bean), e.g.
|
properties or an environment bean), e.g. <programlisting><jdbc:initialize-database data-source="dataSource"
|
||||||
<programlisting><jdbc:initialize-database data-source="dataSource"
|
|
||||||
<emphasis role="bold">enabled="#{systemProperties.INITIALIZE_DATABASE}"</emphasis>>
|
<emphasis role="bold">enabled="#{systemProperties.INITIALIZE_DATABASE}"</emphasis>>
|
||||||
<jdbc:script location="..."/>
|
<jdbc:script location="..."/>
|
||||||
</jdbc:initialize-database></programlisting></para>
|
</jdbc:initialize-database></programlisting></para>
|
||||||
@@ -2979,23 +3042,20 @@ public class DataAccessUnitTestTemplate {
|
|||||||
<para>The first option might be easy if the application is in your
|
<para>The first option might be easy if the application is in your
|
||||||
control, and not otherwise. Some suggestions for how to implement this
|
control, and not otherwise. Some suggestions for how to implement this
|
||||||
are<itemizedlist>
|
are<itemizedlist>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Make the cache initialize lazily on first usage, which
|
<para>Make the cache initialize lazily on first usage, which
|
||||||
improves application startup time</para>
|
improves application startup time</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Have your cache or a separate component that
|
<para>Have your cache or a separate component that initializes
|
||||||
initializes the cache implement <code>Lifecycle</code> or
|
the cache implement <code>Lifecycle</code> or
|
||||||
<code>SmartLifecycle</code>. When the application context
|
<code>SmartLifecycle</code>. When the application context starts
|
||||||
starts up a <code>SmartLifecycle</code> can be automatically
|
up a <code>SmartLifecycle</code> can be automatically started if
|
||||||
started if its <code>autoStartup</code> flag is set,
|
its <code>autoStartup</code> flag is set, and a
|
||||||
and a <code>Lifecycle</code> can be started
|
<code>Lifecycle</code> can be started manually by calling
|
||||||
manually by calling
|
|
||||||
<code>ConfigurableApplicationContext.start()</code> on the
|
<code>ConfigurableApplicationContext.start()</code> on the
|
||||||
enclosing context.
|
enclosing context.</para>
|
||||||
</para>
|
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -3003,10 +3063,9 @@ public class DataAccessUnitTestTemplate {
|
|||||||
custom observer mechanism to trigger the cache initialization.
|
custom observer mechanism to trigger the cache initialization.
|
||||||
<code>ContextRefreshedEvent</code> is always published by the
|
<code>ContextRefreshedEvent</code> is always published by the
|
||||||
context when it is ready for use (after all beans have been
|
context when it is ready for use (after all beans have been
|
||||||
initialized), so that is often a useful hook (this is
|
initialized), so that is often a useful hook (this is how the
|
||||||
how the <code>SmartLifecycle</code> works by default).</para>
|
<code>SmartLifecycle</code> works by default).</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
</itemizedlist></para>
|
</itemizedlist></para>
|
||||||
|
|
||||||
<para>The second option can also be easy. Some suggestions on how to
|
<para>The second option can also be easy. Some suggestions on how to
|
||||||
|
|||||||
Reference in New Issue
Block a user