当使用 DataSource 对象实例化 JdbcTemplate 对象时,它是否打开连接?

When a JdbcTemplate object is instantiated using a DataSource object, does it open a connection?

我的构造函数中有一段代码如下所示:

public class Foo {
    JdbcTemplate jdbcTemplate;

    @Autowired
    public Foo(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate( dataSource );
    }
}

我的问题是:JdbcTemplate对象在创建时,是否从连接池中获取连接并持有使用?

我问这个问题是因为我想避免实例化 Foo 对象占用池中的连接并持有它的情况。这样的安排将意味着我的连接池仅从 bean 实例化中就会迅速耗尽。

您实际上有两个截然不同的问题 post。

我们一个一个来吧。

当使用 DataSource 对象实例化 JdbcTemplate 对象时,它是否打开连接?

不,创建 JdbcTemplate 对象不会打开与数据库的连接。它甚至不创建它。

我们可以看到afterPropertiesSet()方法的源码,在JdbcTemplate(DataSource dataSource)构造函数中调用:

@Override
public void afterPropertiesSet() {
    if (getDataSource() == null) {
        throw new IllegalArgumentException("Property 'dataSource' is required");
    }
    if (!isLazyInit()) {
        getExceptionTranslator();
    }
}

连接实际打开的时刻是调用JdbcTemplateAPI.

的查询方法之一时

例如,execute(ConnectionCallback<T> action) 方法看起来像这样:

@Override
@Nullable
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
    Assert.notNull(action, "Callback object must not be null");

    Connection con = DataSourceUtils.getConnection(obtainDataSource());
    try {
        // Create close-suppressing Connection proxy, also preparing returned Statements.
        Connection conToUse = createConnectionProxy(con);
        return action.doInConnection(conToUse);
    }
    catch (SQLException ex) {
        // Release Connection early, to avoid potential connection pool deadlock
        // in the case when the exception translator hasn't been initialized yet.
        String sql = getSql(action);
        DataSourceUtils.releaseConnection(con, getDataSource());
        con = null;
        throw translateException("ConnectionCallback", sql, ex);
    }
    finally {
        DataSourceUtils.releaseConnection(con, getDataSource());
    }
}

您在问题的实际正文中提出的第二个问题是:

JdbcTemplate 查询方法 API 重用 JDBC 连接还是每次都创建一个新连接?

让我们看看 DataSourceUtils.getConnection(obtainDataSource()); 方法,反过来, 尝试 doGetConnection(dataSource)。后者的源码如下:

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    Assert.notNull(dataSource, "No DataSource specified");

    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(fetchConnection(dataSource));
        }
        return conHolder.getConnection();
    }
    // Else we either got no holder or an empty thread-bound holder here.

    logger.debug("Fetching JDBC Connection from DataSource");
    Connection con = fetchConnection(dataSource);

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        try {
            // 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);
            }
        }
        catch (RuntimeException ex) {
            // Unexpected exception from external delegation call -> close Connection and rethrow.
            releaseConnection(con, dataSource);
            throw ex;
        }
    }

    return con;
}

最后,我们看到:

if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
    conHolder.requested();
    if (!conHolder.hasConnection()) {
        logger.debug("Fetching resumed JDBC Connection from DataSource");
        conHolder.setConnection(fetchConnection(dataSource));
    }
    return conHolder.getConnection();
}

我们到了。您可以清楚地看到 if 连接存在,它被获取并重新使用。

See the full code 如果连接不存在,如何创建连接。

JdbcTemplate API 的 other methods 以类似的方式工作。