开发者社区> 问答> 正文

jdbcTemplate里的StatementCallback等实现类里为什么要实现SqlProvider接口?

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()?

展开
收起
a123456678 2016-03-16 14:31:21 3536 0
1 条回答
写回答
取消 提交回答
  • 代码片断一

    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的代码实现非常精妙。我们通过多阅读,多学习,多研究,并在软件实践中加以运用,一定会提高自身的编程能力。

    2019-07-17 19:03:59
    赞同 展开评论 打赏
问答分类:
SQL
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载