当使用 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 以类似的方式工作。
我的构造函数中有一段代码如下所示:
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 以类似的方式工作。