通过ibatis,获取数据库连接的debug跟踪如下:
核心指出在于BasicDataSource.getConnection()方法。看下该方法:
/**
* Create (if necessary) and return a connection to the database.
*
* @throws SQLException if a database access error occurs
* @return a database connection
*/
public Connection getConnection() throws SQLException {
return createDataSource().getConnection();
}
/**
* Create (if necessary) and return the internal data source we are
* using to manage our connections.
*
* IMPLEMENTATION NOTE - It is tempting to use the
* "double checked locking" idiom in an attempt to avoid synchronizing
* on every single call to this method. However, this idiom fails to
* work correctly in the face of some optimizations that are legal for
* a JVM to perform.
*
* @throws SQLException if the object pool cannot be created.
*/
protected synchronized DataSource createDataSource()
throws SQLException {
if (closed) {
throw new SQLException("Data source is closed");
}
// Return the pool if we have already created it
if (dataSource != null) {
return (dataSource);
}
// create factory which returns raw physical connections
ConnectionFactory driverConnectionFactory = createConnectionFactory();
// create a pool for our connections
createConnectionPool();
// Set up statement pool, if desired
GenericKeyedObjectPoolFactory statementPoolFactory = null;
if (isPoolPreparedStatements()) {
statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
-1, // unlimited maxActive (per key)
GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
0, // maxWait
1, // maxIdle (per key)
maxOpenPreparedStatements);
}
// Set up the poolable connection factory
createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
// Create and return the pooling data source to manage the connections
createDataSourceInstance();
try {
for (int i = 0 ; i < initialSize ; i++) {
connectionPool.addObject();
}
} catch (Exception e) {
throw new SQLNestedException("Error preloading the connection pool", e);
}
return dataSource;
}
该方法是个同步方法。
1.首先判断是否连接池关闭。
2.判断是不是已经存在dataSource,如果有直接返回。
3.通过createConnectionFactory()方法创建连接工厂。
createConnectionFactory方法:
/**
* Creates a JDBC connection factory for this datasource. This method only
* exists so subclasses can replace the implementation class.
*/
protected ConnectionFactory createConnectionFactory() throws SQLException {
// Load the JDBC driver class
Class driverFromCCL = null;
if (driverClassName != null) {
try {
try {
if (driverClassLoader == null) {
Class.forName(driverClassName);
} else {
Class.forName(driverClassName, true, driverClassLoader);
}
} catch (ClassNotFoundException cnfe) {
driverFromCCL = Thread.currentThread(
).getContextClassLoader().loadClass(
driverClassName);
}
} catch (Throwable t) {
String message = "Cannot load JDBC driver class '" +
driverClassName + "'";
logWriter.println(message);
t.printStackTrace(logWriter);
throw new SQLNestedException(message, t);
}
}
// Create a JDBC driver instance
Driver driver = null;
try {
if (driverFromCCL == null) {
driver = DriverManager.getDriver(url);
} else {
// Usage of DriverManager is not possible, as it does not
// respect the ContextClassLoader
driver = (Driver) driverFromCCL.newInstance();
if (!driver.acceptsURL(url)) {
throw new SQLException("No suitable driver", "08001");
}
}
} catch (Throwable t) {
String message = "Cannot create JDBC driver of class '" +
(driverClassName != null ? driverClassName : "") +
"' for connect URL '" + url + "'";
logWriter.println(message);
t.printStackTrace(logWriter);
throw new SQLNestedException(message, t);
}
// Can't test without a validationQuery
if (validationQuery == null) {
setTestOnBorrow(false);
setTestOnReturn(false);
setTestWhileIdle(false);
}
// Set up the driver connection factory we will use
String user = username;
if (user != null) {
connectionProperties.put("user", user);
} else {
log("DBCP DataSource configured without a 'username'");
}
String pwd = password;
if (pwd != null) {
connectionProperties.put("password", pwd);
} else {
log("DBCP DataSource configured without a 'password'");
}
ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
return driverConnectionFactory;
}
首先是初始化jdbc驱动程序。
最后2行代码是创建驱动连接工厂ConnectionFactory。
DriverConnectionFactory类很简单,主要的方法是createConnection,方法如下:
public Connection createConnection() throws SQLException {
return _driver.connect(_connectUri,_props);
}
使用jdbc的Driver实现类来创建数据库连接。
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;
}
5.再下一步是创建连接池中的连接工厂类
createPoolableConnectionFactory方法中的
/**
* Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists
* so subclasses can replace the default implementation.
*
* @param driverConnectionFactory JDBC connection factory
* @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
* @param configuration abandoned connection tracking configuration (null if no tracking)
* @throws SQLException if an error occurs creating the PoolableConnectionFactory
*/
protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
PoolableConnectionFactory connectionFactory = null;
try {
connectionFactory =
new PoolableConnectionFactory(driverConnectionFactory,
connectionPool,
statementPoolFactory,
validationQuery,
validationQueryTimeout,
connectionInitSqls,
defaultReadOnly,
defaultAutoCommit,
defaultTransactionIsolation,
defaultCatalog,
configuration);
validateConnectionFactory(connectionFactory);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
}
}
PoolableConnectionFactory的构造方法中的代码如下:
public PoolableConnectionFactory(
ConnectionFactory connFactory,
ObjectPool pool,
KeyedObjectPoolFactory stmtPoolFactory,
String validationQuery,
int validationQueryTimeout,
Collection connectionInitSqls,
Boolean defaultReadOnly,
boolean defaultAutoCommit,
int defaultTransactionIsolation,
String defaultCatalog,
AbandonedConfig config) {
_connFactory = connFactory;
_pool = pool;
_config = config;
_pool.setFactory(this);
_stmtPoolFactory = stmtPoolFactory;
_validationQuery = validationQuery;
_validationQueryTimeout = validationQueryTimeout;
_connectionInitSqls = connectionInitSqls;
_defaultReadOnly = defaultReadOnly;
_defaultAutoCommit = defaultAutoCommit;
_defaultTransactionIsolation = defaultTransactionIsolation;
_defaultCatalog = defaultCatalog;
}
可以看到通过PoolableConnectionFactory的setFactory方法,将第3步创建的ConnectionFactory和第4步创建的connectionPool 关联起来了。
6.接下来是createDataSourceInstance方法。
该方法如下:
protected void createDataSourceInstance() throws SQLException {
PoolingDataSource pds = new PoolingDataSource(connectionPool);
pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
pds.setLogWriter(logWriter);
dataSource = pds;
}
该方法使用PoolingDataSource将connectionPool包装了下,并
将BasicDataSource的dataSource变量赋值为new PoolingDataSource(connectionPool)。
7.接下来是初始化一定数量的连接池。
8.然后到了PoolingDataSource的getConnection()方法,代码如下。
public Connection getConnection() throws SQLException {
try {
Connection conn = (Connection)(_pool.borrowObject());
if (conn != null) {
conn = new PoolGuardConnectionWrapper(conn);
}
return conn;
} catch(SQLException e) {
throw e;
} catch(NoSuchElementException e) {
throw new SQLNestedException("Cannot get a connection, pool error " + e.getMessage(), e);
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new SQLNestedException("Cannot get a connection, general error", e);
}
}
关键在于GenericObjectPool的borrowObject()方法。