while (conn == null) { lock.lock(); try { 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 // ------------> 走到这里会创建PooledConnection,但是里面会先调用dataSource.getConnection() conn = newPooledConnection(dataSource.getConnection(), this); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { // Cannot create new connection PooledConnectionoldestActiveConnection= state.activeConnections.get(0); longlongestCheckoutTime= 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 = newPooledConnection(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."); } longwt= System.currentTimeMillis(); condition.await(poolTimeToWait, TimeUnit.MILLISECONDS); state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { // set interrupt flag Thread.currentThread().interrupt(); 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."); } thrownewSQLException("PooledDataSource: Could not get a good connection to the database."); } } } } finally { lock.unlock(); }
}
if (conn == null) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } thrownewSQLException("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); }
return (getConnection(url, info, Reflection.getCallerClass())); } privatestatic Connection getConnection( String url, java.util.Properties info, Class<?> caller)throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ ClassLoadercallerCL= caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { // synchronize loading of the correct classloader. if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } }
// Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLExceptionreason=null;
for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { // ----------> driver[className=com.mysql.cj.jdbc.Driver@64030b91] println(" trying " + aDriver.driver.getClass().getName()); Connectioncon= aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } }
public Configuration parse() { if (parsed) { thrownewBuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; }
protectedbooleanlazyLoadingEnabled=false; protectedProxyFactoryproxyFactory=newJavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
protected String databaseId; /** * Configuration factory class. * Used to create Configuration for loading deserialized unread properties. * * @see <a href='https://github.com/mybatis/old-google-code-issues/issues/300'>Issue 300 (google code)</a> */ protected Class<?> configurationFactory;
public Configuration parse() { if (parsed) { thrownewBuilderException("Each XMLConfigBuilder can only be used once."); } // 标记下是否已解析,但是这里是否有线程安全问题 parsed = true; // --------> 解析配置 parseConfiguration(parser.evalNode("/configuration")); return configuration; }
// Include Fragments before parsing XMLIncludeTransformerincludeParser=newXMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode());
public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } elseif (list.size() > 1) { thrownewTooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { returnnull; } }