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

Spring源代码解析(一) spring JDBC

下面我们看看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替我们实现的代码    
            }    
}  


在模板中嵌入的是需要客户化的代码,由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());    
    }    
}   


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

public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)    
        throws DataAccessException {    
    ..........    
    //这里调用了我们上面看到的execute()基本方法,然而这里的回调实现是Spring为我们完成的查询过程    
    return execute(psc, new PreparedStatementCallback() {    
        public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {    
            //准备查询结果集    
            ResultSet rs = null;    
            try {    
            //这里配置SQL参数    
                if (pss != null) {    
                    pss.setValues(ps);    
                }    
          //这里执行的SQL查询    
                rs = ps.executeQuery();    
                ResultSet rsToUse = rs;    
                if (nativeJdbcExtractor != null) {    
                    rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);    
                }    
         //返回需要的记录集合    
                return rse.extractData(rsToUse);    
            }    
            finally {    
        //最后关闭查询的纪录集,对数据库连接的释放在execute()中释放,就像我们在上面分析的看到那样。    
                JdbcUtils.closeResultSet(rs);    
                if (pss instanceof ParameterDisposer) {    
                    ((ParameterDisposer) pss).cleanupParameters();    
                }    
            }    
        }    
    });    
}   

辅助类DataSourceUtils来用来对数据库连接进行管理的主要工具,比如打开和关闭数据库连接等基本操作:


public static Connection doGetConnection(DataSource dataSource) throws SQLException {    
   //把对数据库连接放到事务管理里面进行管理    
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);    
    i