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

问题描述

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

<guid2 isPermaLink="true">
    <value>http://example.com/abc</value>
</guid2>

我的问题是:创建JdbcTemplate对象时,它是否从连接池获取连接并保持使用状态?

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

解决方法

您实际上在这篇文章中有两个不同的问题。

让我们一次吃一次。

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

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

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

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

实际上打开的时刻是您调用JdbcTemplate API的一种查询方法时。

例如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();
}

就在这里。您可以清楚地看到如果存在,则表示该连接已被获取并重新使用。

See the full code关于不存在连接的创建方式。

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...