Jim*_*son 6 java spring jdbc prepared-statement spring-jdbc
SQL 的一项简单优化是重用准备好的语句。您会产生一次解析成本,然后可以PreparedStatement在循环中重用该对象,只需根据需要更改参数即可。Oracle 的 JDBC 教程和许多其他地方都清楚地记录了这一点。
Spring 5 使用时JdbcTemplate似乎使这变得不可能。所有处理 s 的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());
}
}
Run Code Online (Sandbox Code Playgroud)
“有趣”的部分在finally块中:
JdbcUtils.closeStatement(ps);
Run Code Online (Sandbox Code Playgroud)
这使得 JdbcTemplate 完全不可能重用准备好的语句。
我已经有很长一段时间(5 年)没有机会使用 Spring JDBC了,但我不记得这曾经是一个问题。我在一个大型 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);
}
);
Run Code Online (Sandbox Code Playgroud)
但当然,由于硬编码语句关闭调用,第二次会失败。
问题:假设我想继续使用 Spring JDBC,重用准备好的语句的正确方法是什么?
另外,如果有人知道 Spring 为什么这样做(即有一个很好的理由),我想知道。
| 归档时间: |
|
| 查看次数: |
1715 次 |
| 最近记录: |