In JdbcTemplate.batchUpdate(String... sql), I noticed that String concatenation is used inside the BatchUpdateException catch block to construct the error message.
Current Implementation
catch (BatchUpdateException ex) {
String batchExceptionSql = null;
for (int i = 0; i < ex.getUpdateCounts().length; i++) {
if (ex.getUpdateCounts()[i] == Statement.EXECUTE_FAILED) {
// String concatenation in loop
batchExceptionSql = appendSql(batchExceptionSql, sql[i]);
}
}
if (StringUtils.hasLength(batchExceptionSql)) {
this.currSql = batchExceptionSql;
}
throw ex;
}
...
private String appendSql(@Nullable String sql, String statement) {
return (StringUtils.hasLength(sql) ? sql + "; " + statement : statement);
}
Issue
Using String concatenation in a loop creates unnecessary temporary objects. While this happens in the exception path, using StringBuilder is a standard optimization practice in Java.
Proposed Solution
Replace the concatenation logic with StringBuilder:
catch (BatchUpdateException ex) {
int[] updateCounts = ex.getUpdateCounts();
StringBuilder failedSql = new StringBuilder();
int limit = Math.min(updateCounts.length, sql.length);
for (int i = 0; i < limit; i++) {
if (updateCounts[i] == Statement.EXECUTE_FAILED) {
if (failedSql.length() > 0) {
failedSql.append("; ");
}
failedSql.append(sql[i]);
}
}
if (failedSql.length() > 0) {
this.currSql = failedSql.toString();
}
throw ex;
}
Benefits
- Reduces memory allocation during batch failures
- Follows standard Java best practices
- No functional changes / Fully backward compatible
- Handles edge case where
updateCounts.length < sql.length
Comment From: jher235
If this approach looks reasonable, I can submit a small PR with this change. Happy to adjust based on any feedback.
Comment From: bclozel
Please submit a PR. I'll close this issue as superseded by your upcoming PR.