问题描述
sql的一个简单优化是重用已准备好的语句。您只需花费一次解析费用,然后就可以在循环内重用PreparedStatement
对象,只需根据需要更改参数即可。这在https://developer.paypal.com/docs/checkout/integration-features/pay-another-account/和许多其他地方都有明确的记录。
Spring 5在使用JdbcTemplate
时似乎无法实现。处理JdbcTemplate
的程序的所有PreparedStatementCreator
查询和更新方法都会降级为一个execute
方法。这是该方法的全部代码。
public <T> T execute(PreparedStatementCreator psc,PreparedStatementCallback<T> action)
throws DataAccessException {
Assert.notNull(psc,"PreparedStatementCreator must not be null");
Assert.notNull(action,"Callback object must not be null");
if (logger.isDebugEnabled()) {
String sql = getsql(psc);
logger.debug("Executing prepared sql statement" + (sql != null ? " [" + sql + "]" : ""));
}
Connection con = DataSourceUtils.getConnection(obtainDataSource());
PreparedStatement ps = null;
try {
ps = psc.createPreparedStatement(con);
applyStatementSettings(ps);
T result = action.doInPreparedStatement(ps);
handleWarnings(ps);
return result;
}
catch (sqlException ex) {
// Release Connection early,to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
if (psc instanceof Parameterdisposer) {
((Parameterdisposer) psc).cleanupParameters();
}
String sql = getsql(psc);
psc = null;
JdbcUtils.closeStatement(ps);
ps = null;
DataSourceUtils.releaseConnection(con,getDataSource());
con = null;
throw translateException("PreparedStatementCallback",sql,ex);
}
finally {
if (psc instanceof Parameterdisposer) {
((Parameterdisposer) psc).cleanupParameters();
}
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con,getDataSource());
}
}
“有趣”位在finally
块中:
JdbcUtils.closeStatement(ps);
这使得使用JdbcTemplate重用已准备好的语句完全不可能。
距离我有机会使用Spring JDBC已有很长时间(5年),但是我不记得这曾经是一个问题。我在大型sql后端上处理了数百个准备好的语句,我清楚地记得不必为每次执行都重新准备它们。
我想做的是这个
private static final String sqlGetPDFFile = "select id,root_dir,file_path,file_time,file_size from PDFFile where digest=?";
private PreparedStatement psGetPDFFile;
@Autowired
public void setDataSource(DataSource dataSource) throws sqlException
{
Connection con = dataSource.getConnection();
psGetPDFFile = con.prepareStatement(sqlGetPDFFile);
this.tmpl = new JdbcTemplate(dataSource);
}
...
...
List<PDFFile> files =
tmpl.query(
// PreparedStatementCreator
c -> {
psGetPDFFile.setBytes(1,fileDigest);
return psGetPDFFile;
},// RowMapper
(rs,n)->
{
long id = rs.getLong(1);
Path rootDir = Paths.get(rs.getString(2));
Path filePath = Paths.get(rs.getString(3));
FileTime fileTime = FileTime.from(rs.getTimestamp(4).toInstant());
long fileSize = rs.getLong(5);
return new PDFFile(id,fileDigest,rootDir,filePath,fileTime,fileSize);
}
);
但是当然,由于硬编码的语句close调用,第二次失败。
问题:假设我想继续使用Spring JDBC,重用已准备好的语句的正确方法是什么?
此外,如果有人知道Spring为什么要这样做(即有充分的理由),我想知道。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)