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

Spring JdbcTemplate执行过程分析

调用入口

调用JdbcTemplate提供的API都会委托给execute(),代码如下:

public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
		throws DataAccessException {

	Assert.notNull(psc, "PreparedStatementCreator must not be null");
	Assert.notNull(action, "Callback object must not be null");
	if (logger.isDebugEnabled()) {
		String sql = getSql(psc);
		logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
	}

	Connection con = DataSourceUtils.getConnection(getDataSource());
	PreparedStatement ps = null;
	try {
		Connection conToUse = con;
		if (this.nativeJdbcExtractor != null &&
				this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
			conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
		}
		ps = psc.createPreparedStatement(conToUse);
		applyStatementSettings(ps);
		PreparedStatement psToUse = ps;
		if (this.nativeJdbcExtractor != null) {
			psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
		}
		T result = action.doInPreparedStatement(psToUse);
		handleWarnings(ps);
		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.
		if (psc instanceof ParameterDisposer) {
			((ParameterDisposer) psc).cleanupParameters();
		}
		String sql = getSql(psc);
		psc = null;
		JdbcUtils.closeStatement(ps);
		ps = null;
		DataSourceUtils.releaseConnection(con, getDataSource());
		con = null;
		throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
	}
	finally {
		if (psc instanceof ParameterDisposer) {
			((ParameterDisposer) psc).cleanupParameters();
		}
		JdbcUtils.closeStatement(ps);
		DataSourceUtils.releaseConnection(con, getDataSource());
	}
}

?

总结一下可以分为三个步骤:

  1. 获取DataSource的Connection 。
  2. 设置Statement的属性并执行SQL 。
  3. 关闭Connection 。

1.获取Connection

Spring jdbcTemplate 获取Connection 是委托给 DataSourceUtils.getConnection(getDataSource());实现的。里面的核心方法就是调用 dataSource.getConnection()获取。
DBCP的getConnection() 内部是通过GenericObjectPool实现的,PoolableConnectionFactory是pool的工厂负责makeObject():

class BasicDataSource{
    protected void createConnectionPool() {
        // Create an object pool to contain our active connections
        GenericObjectPool gop;
        if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
            gop = new AbandonedObjectPool(null,abandonedConfig);
        }
        else {
            gop = new GenericObjectPool();
        }
        gop.setMaxActive(maxActive);
        gop.setMaxIdle(maxIdle);
        gop.setMinIdle(minIdle);
        gop.setMaxWait(maxWait);
        gop.setTestOnBorrow(testOnBorrow);
        gop.setTestOnReturn(testOnReturn);
        gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        gop.setTestWhileIdle(testWhileIdle);
        connectionPool = gop;
    }
}

?

2.设置Statement的属性并执行SQL

jdbcTempate有一行比较重要的代码applyStatementSettings(ps) 是设置StatementSettings的,包括FetchSize,MaxRows,QueryTimeout等,在某些情况下非常有用。

protected void applyStatementSettings(Statement stmt) throws SQLException {
		int fetchSize = getFetchSize();
		if (fetchSize > 0) {
			stmt.setFetchSize(fetchSize);
		}
		int maxRows = getMaxRows();
		if (maxRows > 0) {
			stmt.setMaxRows(maxRows);
		}
		DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());
	}

?

3.关闭Connection

执行完SQL之后需要关闭connection,jdbcTempalte是委托给 DataSour