diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index f5468988bf..58a460cdb2 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -124,9 +124,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements protected volatile String validationQuery = DEFAULT_VALIDATION_QUERY; protected volatile int validationQueryTimeout = -1; - private volatile boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; - private volatile boolean testOnReturn = DEFAULT_TEST_ON_RETURN; - private volatile boolean testWhileIdle = DEFAULT_WHILE_IDLE; + protected volatile boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; + protected volatile boolean testOnReturn = DEFAULT_TEST_ON_RETURN; + protected volatile boolean testWhileIdle = DEFAULT_WHILE_IDLE; protected volatile boolean poolPreparedStatements = false; protected volatile boolean sharePreparedStatements = false; protected volatile int maxPoolPreparedStatementPerConnectionSize = 10; @@ -1444,7 +1444,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } void initStatement(DruidPooledConnection conn, Statement stmt) throws SQLException { - boolean transaction = !conn.getConnectionHolder().isUnderlyingAutoCommit(); + boolean transaction = !conn.getConnectionHolder().underlyingAutoCommit; int queryTimeout = transaction ? getTransactionQueryTimeout() : getQueryTimeout(); @@ -1600,9 +1600,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements conn.setAutoCommit(defaultAutoCommit); } - if (getDefaultReadOnly() != null) { - if (conn.isReadOnly() != getDefaultReadOnly()) { - conn.setReadOnly(getDefaultReadOnly()); + if (defaultReadOnly != null) { + if (conn.isReadOnly() != defaultReadOnly) { + conn.setReadOnly(defaultReadOnly); } } diff --git a/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java b/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java index d635f21193..6fb3e548f1 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java +++ b/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java @@ -41,43 +41,33 @@ import com.alibaba.druid.util.Utils; * @author wenshao [szujobs@hotmail.com] */ public final class DruidConnectionHolder { - - private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class); + private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class); + public static boolean holdabilityUnsupported = false; protected final DruidAbstractDataSource dataSource; - private final long connectionId; - private final Connection conn; - private final List connectionEventListeners = new CopyOnWriteArrayList(); - private final List statementEventListeners = new CopyOnWriteArrayList(); - protected final long connectTimeMillis; - protected volatile long lastActiveTimeMillis; - private long useCount = 0; - private long keepAliveCheckCount = 0; - - private long lastNotEmptyWaitNanos; - - private final long createNanoSpan; - - private PreparedStatementPool statementPool; - - protected final List statementTrace = new ArrayList(2); - - private final boolean defaultReadOnly; - private final int defaultHoldability; - private final int defaultTransactionIsolation; - - private final boolean defaultAutoCommit; - - private boolean underlyingReadOnly; - private int underlyingHoldability; - private int underlyingTransactionIsolation; - private boolean underlyingAutoCommit; - private boolean discard = false; - - protected final Map variables; - protected final Map globleVariables; - - public static boolean holdabilityUnsupported = false; + protected final long connectionId; + protected final Connection conn; + protected final List connectionEventListeners = new CopyOnWriteArrayList(); + protected final List statementEventListeners = new CopyOnWriteArrayList(); + protected final long connectTimeMillis; + protected volatile long lastActiveTimeMillis; + private long useCount = 0; + private long keepAliveCheckCount = 0; + private long lastNotEmptyWaitNanos; + private final long createNanoSpan; + protected PreparedStatementPool statementPool; + protected final List statementTrace = new ArrayList(2); + protected final boolean defaultReadOnly; + protected final int defaultHoldability; + protected final int defaultTransactionIsolation; + protected final boolean defaultAutoCommit; + protected boolean underlyingReadOnly; + protected int underlyingHoldability; + protected int underlyingTransactionIsolation; + protected boolean underlyingAutoCommit; + protected boolean discard = false; + protected final Map variables; + protected final Map globleVariables; public DruidConnectionHolder(DruidAbstractDataSource dataSource, PhysicalConnectionInfo pyConnectInfo) throws SQLException{ diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 6bed703de5..d190cceb97 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -250,6 +250,12 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat this.setUseGlobalDataSourceStat(value); } } + { + Boolean value = getBoolean(properties, "druid.asyncInit"); // compatible for early versions + if (value != null) { + this.setAsyncInit(value); + } + } { String property = properties.getProperty("druid.filters"); @@ -308,6 +314,17 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } } + { + String property = properties.getProperty("druid.timeBetweenEvictionRunsMillis"); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setTimeBetweenEvictionRunsMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property 'druid.timeBetweenEvictionRunsMillis'", e); + } + } + } { String property = properties.getProperty("druid.maxWaitThreadCount"); if (property != null && property.length() > 0) { @@ -1232,35 +1249,35 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat throw ex; } - if (isTestOnBorrow()) { - boolean validate = testConnectionInternal(poolableConnection.getConnection()); + if (testOnBorrow) { + boolean validate = testConnectionInternal(poolableConnection.conn); if (!validate) { if (LOG.isDebugEnabled()) { LOG.debug("skip not validate connection."); } - Connection realConnection = poolableConnection.getConnection(); + Connection realConnection = poolableConnection.conn; discardConnection(realConnection); continue; } } else { - Connection realConnection = poolableConnection.getConnection(); - if (realConnection.isClosed()) { + Connection realConnection = poolableConnection.conn; + if (poolableConnection.conn.isClosed()) { discardConnection(null); // 传入null,避免重复关闭 continue; } - if (isTestWhileIdle()) { + if (testWhileIdle) { final long currentTimeMillis = System.currentTimeMillis(); - final long lastActiveTimeMillis = poolableConnection.getConnectionHolder().getLastActiveTimeMillis(); + final long lastActiveTimeMillis = poolableConnection.holder.lastActiveTimeMillis; final long idleMillis = currentTimeMillis - lastActiveTimeMillis; - long timeBetweenEvictionRunsMillis = this.getTimeBetweenEvictionRunsMillis(); + long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis; if (timeBetweenEvictionRunsMillis <= 0) { timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; } if (idleMillis >= timeBetweenEvictionRunsMillis) { - boolean validate = testConnectionInternal(poolableConnection.getConnection()); + boolean validate = testConnectionInternal(poolableConnection.conn); if (!validate) { if (LOG.isDebugEnabled()) { LOG.debug("skip not validate connection."); @@ -1273,11 +1290,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } - if (isRemoveAbandoned()) { + if (removeAbandoned) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - poolableConnection.setConnectStackTrace(stackTrace); + poolableConnection.connectStackTrace = stackTrace; poolableConnection.setConnectedTimeNano(); - poolableConnection.setTraceEnable(true); + poolableConnection.traceEnable = true; activeConnectionLock.lock(); try { @@ -1287,7 +1304,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } - if (!this.isDefaultAutoCommit()) { + if (!this.defaultAutoCommit) { poolableConnection.setAutoCommit(false); } @@ -1328,7 +1345,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait); - final int maxWaitThreadCount = getMaxWaitThreadCount(); + final int maxWaitThreadCount = this.maxWaitThreadCount; DruidConnectionHolder holder; try { @@ -1478,7 +1495,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat * 回收连接 */ protected void recycle(DruidPooledConnection pooledConnection) throws SQLException { - final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); + final DruidConnectionHolder holder = pooledConnection.holder; if (holder == null) { LOG.warn("connectionHolder is null"); @@ -1487,20 +1504,20 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (logDifferentThread // && (!isAsyncCloseConnectionEnable()) // - && pooledConnection.getOwnerThread() != Thread.currentThread()// + && pooledConnection.ownerThread != Thread.currentThread()// ) { LOG.warn("get/close not same thread"); } - final Connection physicalConnection = holder.getConnection(); + final Connection physicalConnection = holder.conn; - if (pooledConnection.isTraceEnable()) { + if (pooledConnection.traceEnable) { Object oldInfo = null; activeConnectionLock.lock(); try { - if (pooledConnection.isTraceEnable()) { + if (pooledConnection.traceEnable) { oldInfo = activeConnections.remove(pooledConnection); - pooledConnection.setTraceEnable(false); + pooledConnection.traceEnable = false; } } finally { activeConnectionLock.unlock(); @@ -1512,9 +1529,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } - final boolean isAutoCommit = holder.isUnderlyingAutoCommit(); - final boolean isReadOnly = holder.isUnderlyingReadOnly(); - final boolean testOnReturn = this.isTestOnReturn(); + final boolean isAutoCommit = holder.underlyingAutoCommit; + final boolean isReadOnly = holder.underlyingReadOnly; + final boolean testOnReturn = this.testOnReturn; try { // check need to rollback? @@ -1523,7 +1540,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } // reset holder, restore default settings, clear warnings - boolean isSameThread = pooledConnection.getOwnerThread() == Thread.currentThread(); + boolean isSameThread = pooledConnection.ownerThread == Thread.currentThread(); if (!isSameThread) { final ReentrantLock lock = pooledConnection.lock; lock.lock(); @@ -1536,7 +1553,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat holder.reset(); } - if (holder.isDiscard()) { + if (holder.discard) { return; } @@ -1559,7 +1576,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } if (!enable) { - discardConnection(holder.getConnection()); + discardConnection(holder.conn); return; } @@ -1585,15 +1602,15 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } if (!result) { - JdbcUtils.close(holder.getConnection()); + JdbcUtils.close(holder.conn); LOG.info("connection recyle failed."); } } catch (Throwable e) { holder.clearStatementCache(); - if (!holder.isDiscard()) { + if (!holder.discard) { this.discardConnection(physicalConnection); - holder.setDiscard(true); + holder.discard = true; } LOG.error("recyle error", e); @@ -1610,7 +1627,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat try { for (int i = 0; i < poolingCount; ++i) { DruidConnectionHolder conn = connections[i]; - conn.getStatementPool().clear(); + + if (conn.statementPool != null) { + conn.statementPool.clear(); + } } } finally { lock.unlock(); @@ -1731,7 +1751,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return false; } - e.setLastActiveTimeMillis(lastActiveTimeMillis); + e.lastActiveTimeMillis = lastActiveTimeMillis; connections[poolingCount] = e; incrementPoolingCount(); @@ -2148,9 +2168,38 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat try { physicalConnection = createPhysicalConnection(); setFailContinuous(false); + } catch (OutOfMemoryError e) { + LOG.error("create connection OutOfMemoryError, out memory. ", e); + + errorCount++; + if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) { + // fail over retry attempts + setFailContinuous(true); + if (failFast) { + lock.lock(); + try { + notEmpty.signalAll(); + } finally { + lock.unlock(); + } + } + + if (breakAfterAcquireFailure) { + lock.lock(); + try { + createTaskCount--; + } finally { + lock.unlock(); + } + return; + } + + this.errorCount = 0; // reset errorCount + createSchedulerFuture = createScheduler.schedule(this, timeBetweenConnectErrorMillis, TimeUnit.MILLISECONDS); + return; + } } catch (SQLException e) { - LOG.error("create connection error, url: " + jdbcUrl, e); - System.out.println(); + LOG.error("create connection SQLException, url: " + jdbcUrl, e); errorCount++; if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) { @@ -2180,7 +2229,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return; } } catch (RuntimeException e) { - LOG.error("create connection error", e); + LOG.error("create connection RuntimeException", e); // unknow fatal exception setFailContinuous(true); continue; @@ -2191,7 +2240,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } finally { lock.unlock(); } - LOG.error("create connection error", e); + LOG.error("create connection Error", e); // unknow fatal exception setFailContinuous(true); break; @@ -2266,6 +2315,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } catch (InterruptedException e) { lastCreateError = e; lastErrorTimeMillis = System.currentTimeMillis(); + + LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e); + break; } finally { lock.unlock(); @@ -2277,7 +2329,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat connection = createPhysicalConnection(); setFailContinuous(false); } catch (SQLException e) { - LOG.error("create connection error, url: " + jdbcUrl + ", errorCode " + e.getErrorCode() + LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode() + ", state " + e.getSQLState(), e); errorCount++; @@ -2304,11 +2356,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } } catch (RuntimeException e) { - LOG.error("create connection error", e); + LOG.error("create connection RuntimeException", e); setFailContinuous(true); continue; } catch (Error e) { - LOG.error("create connection error", e); + LOG.error("create connection Error", e); setFailContinuous(true); break; } @@ -2809,13 +2861,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat map.put("id", System.identityHashCode(conn)); map.put("connectionId", connHolder.getConnectionId()); map.put("useCount", connHolder.getUseCount()); - if (connHolder.getLastActiveTimeMillis() > 0) { - map.put("lastActiveTime", new Date(connHolder.getLastActiveTimeMillis())); + if (connHolder.lastActiveTimeMillis > 0) { + map.put("lastActiveTime", new Date(connHolder.lastActiveTimeMillis)); } map.put("connectTime", new Date(connHolder.getTimeMillis())); map.put("holdability", connHolder.getUnderlyingHoldability()); map.put("transactionIsolation", connHolder.getUnderlyingTransactionIsolation()); - map.put("autoCommit", connHolder.isUnderlyingAutoCommit()); + map.put("autoCommit", connHolder.underlyingAutoCommit); map.put("readoOnly", connHolder.isUnderlyingReadOnly()); if (connHolder.isPoolPreparedStatements()) { diff --git a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java index d13715555d..3a57792949 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java +++ b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java @@ -63,19 +63,17 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. protected volatile DruidConnectionHolder holder; protected TransactionInfo transactionInfo; private final boolean dupCloseLogEnable; - private volatile boolean traceEnable = false; + protected volatile boolean traceEnable = false; private boolean disable = false; private boolean closed = false; - private final Thread ownerThread; + protected final Thread ownerThread; private long connectedTimeMillis; private long connectedTimeNano; private volatile boolean running = false; - private volatile boolean abandoned = false; - private StackTraceElement[] connectStackTrace; - - private Throwable disableError = null; + protected StackTraceElement[] connectStackTrace; + protected Throwable disableError = null; public ReentrantLock lock = new ReentrantLock(); @@ -205,7 +203,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. @Override public Connection getConnection() { - if (!holder.isUnderlyingAutoCommit()) { + if (!holder.underlyingAutoCommit) { createTransactionInfo(); } @@ -706,7 +704,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { - if (autoCommit == holder.isUnderlyingAutoCommit()) { + if (autoCommit == holder.underlyingAutoCommit) { return; } } @@ -871,7 +869,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. public DatabaseMetaData getMetaData() throws SQLException { checkState(); - if (!holder.isUnderlyingAutoCommit()) { + if (!holder.underlyingAutoCommit) { createTransactionInfo(); } @@ -999,7 +997,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. public int getHoldability() throws SQLException { checkState(); - if (!holder.isUnderlyingAutoCommit()) { + if (!holder.underlyingAutoCommit) { createTransactionInfo(); }