日期:2014-05-16  浏览次数:20485 次

Spring源代码解析(三):Spring JDBC
引用自博客:http://jiwenke-spring.blogspot.com/
下面我们看看Spring JDBC相关的实现,
在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数据库操作方法,比如查询,更新等,而且在Spring中,有许多类似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看来这是Rod.Johnson的惯用手法,一般而言这种Template中都是通过回调函数CallBack类的使用来完成功能的,客户需要在回调接口中实现自己需要的定制行为,比如使用客户想要用的SQL语句等。不过往往Spring通过这种回调函数的实现已经为我们提供了许多现成的方法供客户使用。一般来说回调函数的用法采用匿名类的方式来实现,比如:

JdbcTemplate = new JdbcTemplate(datasource);   
jdbcTemplate.execute(new CallBack(){   
            public CallbackInterfacedoInAction(){   
               ......   
               //用户定义的代码或者说Spring替我们实现的代码   
            }   
}  

    JdbcTemplate = new JdbcTemplate(datasource);
    jdbcTemplate.execute(new CallBack(){
                public CallbackInterfacedoInAction(){
                   ......
                   //用户定义的代码或者说Spring替我们实现的代码
                }
    }


在模板中嵌入的是需要客户化的代码,由Spring来作或者需要客户程序亲自动手完成。下面让我们具体看看在JdbcTemplate中的代码是怎样完成使命的,我们举JdbcTemplate.execute()为例,这个方法是在JdbcTemplate中被其他方法调用的基本方法之一,客户程序往往用这个方法来执行基本的SQL语句:
public Object execute(ConnectionCallback action) throws DataAccessException {   
    //这里得到数据库联接   
    Connection con = DataSourceUtils.getConnection(getDataSource());   
    try {   
        Connection conToUse = con;   
        //有些特殊的数据库,需要我们使用特别的方法取得datasource   
        if (this.nativeJdbcExtractor != null) {   
            // Extract native JDBC Connection, castable to OracleConnection or the like.   
            conToUse = this.nativeJdbcExtractor.getNativeConnection(con);   
        }   
        else {   
            // Create close-suppressing Connection proxy, also preparing returned Statements.   
            conToUse = createConnectionProxy(con);   
        }   
    //这里调用的是传递进来的匿名类的方法,也就是用户程序需要实现CallBack接口的地方。   
        return action.doInConnection(conToUse);   
    }   
    catch (SQLException ex) {   
        //如果捕捉到数据库异常,把数据库联接释放,同时抛出一个经过Spring转换过的Spring数据库异常,   
        //我们知道,Spring做了一个有意义的工作是把这些数据库异常统一到自己的异常体系里了。   
        DataSourceUtils.releaseConnection(con, getDataSource());   
        con = null;   
        throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);   
    }   
    finally {   
        //最后不管怎样都会把数据库连接释放   
        DataSourceUtils.releaseConnection(con, getDataSource());   
    }   
}  

    public Object execute(ConnectionCallback action) throws DataAccessException {
        //这里得到数据库联接
        Connection con = DataSourceUtils.getConnection(getDataSource());
        try {
            Connection conToUse = con;
            //有些特殊的数据库,需要我们使用特别的方法取得datasource
            if (this.nativeJdbcExtractor != null) {
                // Extract native JDBC Connection, castable to OracleConnection or the like.
                conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
            }
            else {
                // Create close-suppressing Connection proxy, also preparing returned Statements.
                conToUse = createConnectionProxy(con);
            }
        //这里调用的是传递进来的匿名类的方法,也就是用户程序需要实现CallBack接口的地方。
            return action.doInConnection(conToUse);
        }
        catch (SQLException ex) {
            //如果捕捉到数据库异常,把数据库联接释放,同时抛出一个经过Spring转换过的Spring数据库异常,
            //我们知道,Spring做了一个有意义的工作是把这些数据库异常统一到自己的异常体系里了。
            DataSourceUtils.releaseConnection(con, getDataSource());
            con = null;
            throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
        }
        finally {
            //最后不管怎样都会把数据库连接释放
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }


对于JdbcTemplate中给出的其他方法,比如query,update,execute等的实现,我们看看query():

public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)   
        throws DataAcc