xml形式配置DataSource
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="/com/cn/cs/config.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${oracle.driver}"/> <property name="url" value="${oracle.url}"/> <property name="username" value="${oracle.username}"/> <property name="password" value="${oracle.password}"/> <property name="poolMaximumActiveConnections" value="10"/> <!--最大活躍連接數 --> <property name="poolMaximumIdleConnections" value="5"/> <!--最大空閑連接數--> <property name="poolTimeToWait" value="20000"/> <!--創建連接時最大等待時間20s--> </dataSource> </environment> </environments> <mappers> <mapper resource="/com/cn/cs/mapping/UserCsMapper.xml"/> </mappers>
</configuration>
mybatis中DataSource節點有一個 type屬性. 有三個可選值: pooled(連接池), unpooled(非連接池), jndi
mybatis內部定義了一個DataSourceFactory接口
public interface DataSourceFactory { void setProperties(Properties props); DataSource getDataSource(); }
根據type 屬性值分別對應實現類.
pooled --> PooledDataSourceFactory
unpooled --> UnpooledDataSourceFactory
jndi--> JndiDataSourceFactory
這三個實現類都實現了 DataSourceFactory 的 DataSource getDataSource()方法.
PooledDataSourceFactory.getDataSource() 返回 PooledDataSource.
UnpooledDataSourceFactory.getDataSource() 返回 UnpooledDataSource
JndiDataSourceFactory.getDataSource() 返回 環境中的 DataSource
DataSource 將會保存在Environment 的靜態內部類Builder中.
連接池的初始化
dataSource 此時只會保存好配置信息.連接池此時並沒有創建好連接.只有當程序在調用操作數據庫的方法時,才會出示化連接.
管理連接池的類為PooledDateSource 這個類中有一個獲取連接的方法.
這個方法會先判斷是否有空閑連接,有的話會直接將連接取出來.如果沒有則判斷當前活躍的連接是否大於最大空閑連接數.如果小於則創建一個新的連接.
否則將舊的連接刪掉一個,並創建一個新的連接.
private PooledConnection popConnection(String username, String password) throws SQLException { boolean countedWait = false; PooledConnection conn = null; long t = System.currentTimeMillis(); int localBadConnectionCount = 0; while (conn == null) { synchronized (state) { if (!state.idleConnections.isEmpty()) { // Pool has available connection conn = state.idleConnections.remove(0); if (log.isDebugEnabled()) { log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); } } else { // Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) { // Can create new connection conn = new PooledConnection(dataSource.getConnection(), this); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { // Cannot create new connection PooledConnection oldestActiveConnection = state.activeConnections.get(0); long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); if (longestCheckoutTime > poolMaximumCheckoutTime) { // Can claim overdue connection state.claimedOverdueConnectionCount++; state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; state.accumulatedCheckoutTime += longestCheckoutTime; state.activeConnections.remove(oldestActiveConnection); if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { try { oldestActiveConnection.getRealConnection().rollback(); } catch (SQLException e) { /* Just log a message for debug and continue to execute the following statement like nothing happened. Wrap the bad connection with a new PooledConnection, this will help to not interrupt current executing thread and give current thread a chance to join the next competition for another valid/good database connection. At the end of this loop, bad {@link @conn} will be set as null. */ log.debug("Bad connection. Could not roll back"); } } conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this); conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp()); conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp()); oldestActiveConnection.invalidate(); if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else { // Must wait try { if (!countedWait) { state.hadToWaitCount++; countedWait = true; } if (log.isDebugEnabled()) { log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection."); } long wt = System.currentTimeMillis(); state.wait(poolTimeToWait); state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { break; } } } } if (conn != null) { // ping to server and check the connection is valid or not if (conn.isValid()) { if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password)); conn.setCheckoutTimestamp(System.currentTimeMillis()); conn.setLastUsedTimestamp(System.currentTimeMillis()); state.activeConnections.add(conn); state.requestCount++; state.accumulatedRequestTime += System.currentTimeMillis() - t; } else { if (log.isDebugEnabled()) { log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); } state.badConnectionCount++; localBadConnectionCount++; conn = null; if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } throw new SQLException("PooledDataSource: Could not get a good connection to the database."); } } } } } if (conn == null) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } throw new SQLException("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } return conn; }