RESOLVED - issue BATCH-687: BatchUpdateItemWriter should fail if any of the statements does not update any rows (at least by default).

This commit is contained in:
dsyer
2008-06-25 11:58:55 +00:00
parent 761120e1ab
commit 786de6f5a8
2 changed files with 70 additions and 6 deletions

View File

@@ -17,14 +17,16 @@ package org.springframework.batch.item.database;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.List;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.util.Assert;
@@ -67,6 +69,17 @@ public class BatchSqlUpdateItemWriter extends AbstractTransactionalResourceItemW
private String sql;
private boolean assertUpdates = true;
/**
* Public setter for the flag that determines whether an assertion is made
* that all items cause at least one row to be updated.
* @param assertUpdates the flag to set. Defaults to true;
*/
public void setAssertUpdates(boolean assertUpdates) {
this.assertUpdates = assertUpdates;
}
/**
* Public setter for the query string to execute on write. The parameters
* should correspond to those known to the
@@ -104,11 +117,15 @@ public class BatchSqlUpdateItemWriter extends AbstractTransactionalResourceItemW
/**
* Create and execute batch prepared statement.
* @throws EmptyResultDataAccessException if any of the items does not cause an update
*/
protected void doFlush() {
final Set processed = getProcessed();
protected void doFlush() throws EmptyResultDataAccessException {
final List processed = new ArrayList(getProcessed());
if (!processed.isEmpty()) {
jdbcTemplate.execute(sql, new PreparedStatementCallback() {
int[] values = (int[]) jdbcTemplate.execute(sql, new PreparedStatementCallback() {
public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
for (Iterator iterator = processed.iterator(); iterator.hasNext();) {
Object item = (Object) iterator.next();
@@ -118,7 +135,19 @@ public class BatchSqlUpdateItemWriter extends AbstractTransactionalResourceItemW
return ps.executeBatch();
}
});
if (assertUpdates) {
for (int i = 0; i < values.length; i++) {
int value = values[i];
if (value == 0) {
throw new EmptyResultDataAccessException("Item " + i + " of " + values.length
+ " did not update any rows: [" + processed.get(i) + "]", 1);
}
}
}
}
}
protected String getResourceKey() {
@@ -130,7 +159,7 @@ public class BatchSqlUpdateItemWriter extends AbstractTransactionalResourceItemW
*/
protected void doWrite(Object output) {
}
/**
* No-op.
*/

View File

@@ -29,6 +29,7 @@ import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.context.RepeatContextSupport;
import org.springframework.batch.repeat.support.RepeatSynchronizationManager;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
@@ -133,9 +134,14 @@ public class BatchSqlUpdateItemWriterTests extends TestCase {
/**
* Test method for
* {@link org.springframework.batch.item.database.BatchSqlUpdateItemWriter#flush()}.
* @throws SQLException
*/
public void testFlush() {
public void testFlush() throws SQLException {
assertTrue(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
ps.addBatch(); // there is one item in the buffer to start
control.setVoidCallable();
control.expectAndReturn(ps.executeBatch(), new int[0]);
control.replay();
writer.flush();
assertFalse(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
assertEquals(2, list.size());
@@ -149,6 +155,10 @@ public class BatchSqlUpdateItemWriterTests extends TestCase {
*/
public void testWriteAndFlush() throws Exception {
assertTrue(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
ps.addBatch();
control.setVoidCallable(2);
control.expectAndReturn(ps.executeBatch(), new int[] { 123 });
control.replay();
writer.write("bar");
writer.flush();
assertFalse(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
@@ -156,6 +166,31 @@ public class BatchSqlUpdateItemWriterTests extends TestCase {
assertTrue(list.contains("SQL"));
}
/**
* Test method for
* {@link org.springframework.batch.item.database.BatchSqlUpdateItemWriter#flush()}.
* @throws Exception
*/
public void testWriteAndFlushWithEmptyUpdate() throws Exception {
assertTrue(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
ps.addBatch();
control.setVoidCallable(2);
control.expectAndReturn(ps.executeBatch(), new int[] { 0 });
control.replay();
writer.write("bar");
try {
writer.flush();
fail("Expected EmptyResultDataAccessException");
} catch (EmptyResultDataAccessException e) {
// expected
String message = e.getMessage();
assertTrue("Wrong message: "+message, message.indexOf("did not update")>=0);
}
assertFalse(TransactionSynchronizationManager.hasResource(writer.getResourceKey()));
assertEquals(3, list.size());
assertTrue(list.contains("SQL"));
}
public void testWriteAndFlushWithFailure() throws Exception {
final RuntimeException ex = new RuntimeException("bar");
writer.setItemPreparedStatementSetter(new ItemPreparedStatementSetter() {