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替我们实现的代码 } }
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 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(); } } } }); }
public static Connection doGetConnection(DataSource dataSource) throws SQLException { //把对数据库连接放到事务管理里面进行管理 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { conHolder.requested(); if (!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection(dataSource.getConnection()); } return conHolder.getConnection(); } // 这里得到需要的数据库连接,在配置文件中定义好的。 logger.debug("Fetching JDBC Connection from DataSource"); Connection con = dataSource.getConnection(); if (TransactionSynchronizationManager.isSynchronizationActive()) { logger.debug("Registering transaction synchronization for JDBC Connection"); // Use same Connection for further JDBC actions within the transaction. // Thread-bound object will get removed by synchronization at transaction completion. ConnectionHolder holderToUse = conHolder; if (holderToUse == null) { holderToUse = new ConnectionHolder(con); } else { holderToUse.setConnection(con); } holderToUse.requested(); TransactionSynchronizationManager.registerSynchronization( new ConnectionSynchronization(holderToUse, dataSource)); holderToUse.setSynchronizedWithTransaction(true); if (holderToUse != conHolder) { TransactionSynchronizationManager.bindResource(dataSource, holderToUse); } } return con; }
public abstract class JdbcAccessor implements InitializingBean { /** 这里是我们依赖注入数据库数据源的地方。 */ private DataSource dataSource; /** Helper to translate SQL exceptions to DataAccessExceptions */ private SQLExceptionTranslator exceptionTranslator; private boolean lazyInit = true; ........ }
public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException { //如果声明已经被编译过,则该声明无效 if (isCompiled()) { throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled"); } //这里对参数值进行声明定义 this.declaredParameters.add(param);
/** List of SqlParameter objects */ private List declaredParameters = new LinkedList();
public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException { validateNamedParameters(paramMap); Object[] parameters = NamedParameterUtils.buildValueArray(getSql(), paramMap); RowMapper rowMapper = newRowMapper(parameters, context); String sqlToUse = NamedParameterUtils.substituteNamedParameters(getSql(), new MapSqlParameterSource(paramMap)); //我们又看到了JdbcTemplate,这里使用JdbcTemplate来完成对数据库的查询操作,所以我们说JdbcTemplate是基本的操作类。 return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, parameters), rowMapper); }
public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException { return execute(new SimplePreparedStatementCreator(sql), action); }
public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException { LobCreator lobCreator = this.lobHandler.getLobCreator(); try { //这是一个模板方法,具体需要由客户程序实现 setValues(ps, lobCreator); return new Integer(ps.executeUpdate()); } finally { lobCreator.close(); } } //定义的需要客户程序实现的虚函数 protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException, DataAccessException;
public void setBlobAsBinaryStream( PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength) throws SQLException { //通过JDBC来完成对BLOB数据的操作,对Oracle,Spring提供了OracleLobHandler来支持BLOB操作。 ps.setBinaryStream(paramIndex, binaryStream, contentLength); ........ }