public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
Assert.notNull(sql, "SQL must not be null");
Assert.notNull(rse, "ResultSetExtractor must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL query [" + sql + "]");
}
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
public T doInStatement(Statement stmt) throws SQLException {
ResultSet rs = null;
try {
rs = stmt.executeQuery(sql);
ResultSet rsToUse = rs;
if (nativeJdbcExtractor != null) {
rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
}
return rse.extractData(rsToUse);
}
finally {
JdbcUtils.closeResultSet(rs);
}
}
public String getSql() {
return sql;
}
}
return execute(new QueryStatementCallback());
}
class QueryStatementCallback implements StatementCallback, SqlProvider
哪里有用到SqlProvider里的getSql()?
代码片断一
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
Assert.notNull(sql, "SQL must not be null");
Assert.notNull(rse, "ResultSetExtractor must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL query [" + sql + "]");
}
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
public T doInStatement(Statement stmt) throws SQLException {
ResultSet rs = null;
try {
rs = stmt.executeQuery(sql);
ResultSet rsToUse = rs;
if (nativeJdbcExtractor != null) {
rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
}
return rse.extractData(rsToUse);
}
finally {
JdbcUtils.closeResultSet(rs);
}
}
public String getSql() {
return sql;
}
}
return execute(new QueryStatementCallback());
}
代码片断二
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
stmt = conToUse.createStatement();
applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
T result = action.doInStatement(stmtToUse);
handleWarnings(stmt);
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.
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
代码片断三
/**
* Determine SQL from potential provider object.
* @param sqlProvider object that's potentially a SqlProvider
* @return the SQL string, or <code>null</code>
* @see SqlProvider
*/
private static String getSql(Object sqlProvider) {
if (sqlProvider instanceof SqlProvider) {
return ((SqlProvider) sqlProvider).getSql();
}
else {
return null;
}
}
代码片断四
package org.springframework.jdbc.core;
/**
* Interface to be implemented by objects that can provide SQL strings.
*
* <p>Typically implemented by PreparedStatementCreators, CallableStatementCreators
* and StatementCallbacks that want to expose the SQL they use to create their
* statements, to allow for better contextual information in case of exceptions.
*
* @author Juergen Hoeller
* @since 16.03.2004
* @see PreparedStatementCreator
* @see CallableStatementCreator
* @see StatementCallback
*/
public interface SqlProvider {
/**
* Return the SQL string for this object, i.e.
* typically the SQL used for creating statements.
* @return the SQL string, or <code>null</code>
*/
String getSql();
}
执行代码片断一的query方法execute(newQueryStatementCallback())会调用代码片断二的方法。execute方法的异常处理中有throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);此处getSql(action)就需要使用SqlProvider里的getSql()。getSql(action)方法见代码片断三。
接口SqlProvider定义见代码片断四。SqlProvider接口注释中写道:
Typically implemented by PreparedStatementCreators, CallableStatementCreators and StatementCallbacks that want to expose the SQL they use to create their statements, to allow for better contextual information in case of exceptions.
此处QueryStatementCallback实现SqlProvider接口的作用是,如果出现异常,将告知当前执行的sql。这样就很巧妙地通过回调接口来获取相关数据,供调用者使用。这也是模板方法(Template method)模式的应用。
由此可见,spring的代码实现非常精妙。我们通过多阅读,多学习,多研究,并在软件实践中加以运用,一定会提高自身的编程能力。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。