You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to use the jdbcTemplate.batchUpdate and would like to know the exact failed statement.
Issues
Trying to catch the BatchUpdateException which contains the counters does not work because the BatchUpdateException gets removed from the exception stack.
Even when the BatchUpdateException gets returned it only contains the counters of the current batch. The successful batch counts need to be communicated back to the caller as well.
Code to reproduce the problem
I use this table to quickly get a unique constraint exception
createtablebatch_test (
id numberprimary key
);
Configuration
Spring: 5.1.3.RELEASE
Database: Oracle 18c
Code trying to catch the BatchUpdateException
finalList<Integer> primaryKeys = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 7, 8, 9);
try {
returnjdbcTemplate.batchUpdate(
"insert into batch_test values (?)",
primaryKeys,
4,
(ps, primaryKey) -> {
ps.setInt(1, primaryKey);
}
);
} catch (finalDataAccessExceptione) {
finalThrowablecause = e.getCause();
if (causeinstanceofBatchUpdateException) {
finalBatchUpdateExceptionbatchUpdateException = (BatchUpdateException) cause;
finallong[] updateCounts = batchUpdateException.getLargeUpdateCounts();
// log the exact one that failedfor (intindex = 0; index < updateCounts.length; index++) {
if (updateCounts[index] == Statement.EXECUTE_FAILED) {
logger.debug("The insert of element " + index + " of the array failed");
}
}
if (updateCounts.length < primaryKeys.size()) {
logger.debug("The insert of elements " + (updateCounts.length - 1)
+ " to " + (primaryKeys.size() - 1) + " of the array failed");
}
}
throwe;
}
The original stack sqlEx gets overridden with the next exception and thus the information of the BatchUpdateException gets lost.
I understand the intent to translate the cause into an exception that is a little more meaningful, but IMHO the original BatchUpdateException should not be trashed.
Wherever a new exception is created the original exception should be used for the stack. So instead of:
rowsAffected needs to be communicated back to the caller to pinpoint the problematic update
Workaround
My current solution consist of writing my own Translator, overriding the doTranslate method and setting the translator when I create the jdbcTemplate Bean
publicclassBatchUpdateExceptionTranslatorextendsSQLErrorCodeSQLExceptionTranslator {
@Override@NullableprotectedDataAccessExceptiondoTranslate(Stringtask, @NullableStringsql, SQLExceptionex) {
// exchanging sqlEx with ex whenever creating a new Exception
}
}
If anyone is coming here for the work around (I am using spring-jdbc-5.3.29.jar, oracle8-19.3.0.0.jar, Oracle 19, JDK 8) and has the "second issue" (batch size < collection size), then the above sample needs to be adapted.
I am trying to insert ~40,000 records and Oracle is throwing ORA-00001: unique constraint (..) violated. In order to get the failed row I need to set "batch size = collection.size". The return results array only contains successes, so the bad row (I assume) is the new row, which means that collection.get(update.length) should be reported.
I don't know if everything in this issue is still current.
Trying to catch the BatchUpdateException which contains the counters does not work because the BatchUpdateException gets removed from the exception stack
This no longer seems to be the case. BatchUpdateException gets passed as a cause.
Even when the BatchUpdateException gets returned it only contains the counters of the current batch. The successful batch counts need to be communicated back to the caller as well.
I have three proposals how this could be solved:
Add an additional exception (eg. BatchUpdateDetailsException) in the stack that wraps BatchUpdateException
Add a suppressed exception to BatchUpdateException, eg. BatchUpdateDetailsException
Add a next exception to BatchUpdateException, eg. BatchUpdateDetailsException
Affects: 3.0.0.M1 to 5.2.0.RELEASE
Goal
I'm trying to use the jdbcTemplate.batchUpdate and would like to know the exact failed statement.
Issues
Code to reproduce the problem
I use this table to quickly get a unique constraint exception
Configuration
Spring: 5.1.3.RELEASE
Database: Oracle 18c
Code trying to catch the BatchUpdateException
Possible solutions
The problem I'm having happens here:
https://github.com/spring-projects/spring-framework/blame/master/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java#L179
The original stack
sqlEx
gets overridden with the next exception and thus the information of the BatchUpdateException gets lost.I understand the intent to translate the cause into an exception that is a little more meaningful, but IMHO the original BatchUpdateException should not be trashed.
Wherever a new exception is created the original exception should be used for the stack. So instead of:
the original exception should be used:
The second issue is probably here:
https://github.com/spring-projects/spring-framework/blob/master/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java#L1059
rowsAffected
needs to be communicated back to the caller to pinpoint the problematic updateWorkaround
My current solution consist of writing my own Translator, overriding the doTranslate method and setting the translator when I create the jdbcTemplate Bean
The second issue cannot be fixed as easily. Either avoid the use of the batched update or set the batch size very high to not run into that problem
The text was updated successfully, but these errors were encountered: