HSQLDB PreparedStatement caching improvements

This commit is contained in:
catbref 2020-09-24 12:45:37 +01:00
parent d0da5d7c48
commit 21f48fba5f
2 changed files with 47 additions and 36 deletions

View File

@ -446,10 +446,21 @@ public class HSQLDBRepository implements Repository {
* *
* See org.hsqldb.StatementManager for more details. * See org.hsqldb.StatementManager for more details.
*/ */
if (!this.preparedStatementCache.containsKey(sql)) PreparedStatement preparedStatement = this.preparedStatementCache.get(sql);
this.preparedStatementCache.put(sql, this.connection.prepareStatement(sql)); if (preparedStatement == null || preparedStatement.isClosed()) {
if (preparedStatement != null)
// This shouldn't occur, so log, but recompile
LOGGER.debug(() -> String.format("Recompiling closed PreparedStatement: %s", sql));
return this.connection.prepareStatement(sql); preparedStatement = this.connection.prepareStatement(sql);
this.preparedStatementCache.put(sql, preparedStatement);
} else {
// Clean up ready for reuse
preparedStatement.clearBatch();
preparedStatement.clearParameters();
}
return preparedStatement;
} }
/** /**
@ -465,9 +476,8 @@ public class HSQLDBRepository implements Repository {
public ResultSet checkedExecute(String sql, Object... objects) throws SQLException { public ResultSet checkedExecute(String sql, Object... objects) throws SQLException {
PreparedStatement preparedStatement = this.prepareStatement(sql); PreparedStatement preparedStatement = this.prepareStatement(sql);
// Close the PreparedStatement when the ResultSet is closed otherwise there's a potential resource leak. // We don't close the PreparedStatement when the ResultSet is closed because we cached PreparedStatements now.
// We can't use try-with-resources here as closing the PreparedStatement on return would also prematurely close the ResultSet. // They are cleaned up when connection/session is closed.
preparedStatement.closeOnCompletion();
long beforeQuery = this.slowQueryThreshold == null ? 0 : System.currentTimeMillis(); long beforeQuery = this.slowQueryThreshold == null ? 0 : System.currentTimeMillis();
@ -556,36 +566,35 @@ public class HSQLDBRepository implements Repository {
if (batchedObjects == null || batchedObjects.isEmpty()) if (batchedObjects == null || batchedObjects.isEmpty())
return 0; return 0;
try (PreparedStatement preparedStatement = this.prepareStatement(sql)) { PreparedStatement preparedStatement = this.prepareStatement(sql);
for (Object[] objects : batchedObjects) { for (Object[] objects : batchedObjects) {
this.bindStatementParams(preparedStatement, objects); this.bindStatementParams(preparedStatement, objects);
preparedStatement.addBatch(); preparedStatement.addBatch();
}
long beforeQuery = this.slowQueryThreshold == null ? 0 : System.currentTimeMillis();
int[] updateCounts = preparedStatement.executeBatch();
if (this.slowQueryThreshold != null) {
long queryTime = System.currentTimeMillis() - beforeQuery;
if (queryTime > this.slowQueryThreshold) {
LOGGER.info(() -> String.format("HSQLDB query took %d ms: %s", queryTime, sql), new SQLException("slow query"));
logStatements();
}
}
int totalCount = 0;
for (int i = 0; i < updateCounts.length; ++i) {
if (updateCounts[i] < 0)
throw new SQLException("Database returned invalid row count");
totalCount += updateCounts[i];
}
return totalCount;
} }
long beforeQuery = this.slowQueryThreshold == null ? 0 : System.currentTimeMillis();
int[] updateCounts = preparedStatement.executeBatch();
if (this.slowQueryThreshold != null) {
long queryTime = System.currentTimeMillis() - beforeQuery;
if (queryTime > this.slowQueryThreshold) {
LOGGER.info(() -> String.format("HSQLDB query took %d ms: %s", queryTime, sql), new SQLException("slow query"));
logStatements();
}
}
int totalCount = 0;
for (int i = 0; i < updateCounts.length; ++i) {
if (updateCounts[i] < 0)
throw new SQLException("Database returned invalid row count");
totalCount += updateCounts[i];
}
return totalCount;
} }
/** /**

View File

@ -60,7 +60,9 @@ public class HSQLDBSaver {
*/ */
public boolean execute(HSQLDBRepository repository) throws SQLException { public boolean execute(HSQLDBRepository repository) throws SQLException {
String sql = this.formatInsertWithPlaceholders(); String sql = this.formatInsertWithPlaceholders();
try (PreparedStatement preparedStatement = repository.prepareStatement(sql)) {
try {
PreparedStatement preparedStatement = repository.prepareStatement(sql);
this.bindValues(preparedStatement); this.bindValues(preparedStatement);
return preparedStatement.execute(); return preparedStatement.execute();