mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
handle OutOfMemoryError, use field replace getter&setter.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
|
||||
private final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
|
||||
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<Statement> statementTrace = new ArrayList<Statement>(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<String, Object> variables;
|
||||
protected final Map<String, Object> globleVariables;
|
||||
|
||||
public static boolean holdabilityUnsupported = false;
|
||||
protected final long connectionId;
|
||||
protected final Connection conn;
|
||||
protected final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
|
||||
protected final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
|
||||
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<Statement> statementTrace = new ArrayList<Statement>(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<String, Object> variables;
|
||||
protected final Map<String, Object> globleVariables;
|
||||
|
||||
public DruidConnectionHolder(DruidAbstractDataSource dataSource, PhysicalConnectionInfo pyConnectInfo)
|
||||
throws SQLException{
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user