diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 501da678bd..be775705bb 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -218,8 +218,6 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements protected final ReentrantLock lock = new ReentrantLock(true); - protected int modCount = 0; - protected AtomicLong createCount = new AtomicLong(); protected AtomicLong destroyCount = new AtomicLong(); @@ -227,10 +225,6 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements return isOracle; } - protected int getModCount() { - return modCount; - } - public void setOracle(boolean isOracle) { if (inited) { throw new IllegalStateException(); @@ -1298,9 +1292,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements public void initPhysicalConnection(Connection conn) throws SQLException { if (conn.getAutoCommit() != defaultAutoCommit) { - conn.setAutoCommit(defaultAutoCommit); + conn.setAutoCommit(defaultAutoCommit); } - + if (getDefaultReadOnly() != null) { if (conn.isReadOnly() != getDefaultReadOnly()) { conn.setReadOnly(getDefaultReadOnly()); diff --git a/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java b/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java index 745cd9b8e7..f8dba8ef5b 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java +++ b/src/main/java/com/alibaba/druid/pool/DruidConnectionHolder.java @@ -56,10 +56,8 @@ public final class DruidConnectionHolder { private int underlyingHoldability; private int underlyingTransactionIsolation; private boolean underlyingAutoCommit; - private final int modCount; public DruidConnectionHolder(DruidAbstractDataSource dataSource, Connection conn) throws SQLException{ - this.modCount = dataSource.getModCount(); this.dataSource = dataSource; this.conn = conn; @@ -82,10 +80,6 @@ public final class DruidConnectionHolder { this.defaultReadOnly = underlyingReadOnly; } - public int getModCount() { - return modCount; - } - public boolean isUnderlyingReadOnly() { return underlyingReadOnly; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index ba443c8f5e..e19f96f786 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -637,9 +637,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (isRemoveAbandoned()) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - activeConnections.put(poolalbeConnection, - new ActiveConnectionTraceInfo(poolalbeConnection, System.currentTimeMillis(), - stackTrace)); + activeConnections.put(poolalbeConnection, new ActiveConnectionTraceInfo(System.currentTimeMillis(), + stackTrace)); poolalbeConnection.setTraceEnable(true); } @@ -768,7 +767,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat * 回收连接 */ protected void recycle(DruidPooledConnection pooledConnection) throws SQLException { - final Connection conn = pooledConnection.getConnection(); final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); if (holder == null) { @@ -776,6 +774,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return; } + final Connection physicalConnection = holder.getConnection(); + if (pooledConnection.isTraceEnable()) { ActiveConnectionTraceInfo oldInfo = activeConnections.remove(pooledConnection); if (oldInfo == null) { @@ -786,18 +786,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } try { - // 第一步,检查连接是否关闭 - if (conn == null) { - lock.lockInterruptibly(); - try { - activeCount--; - closeCount++; - } finally { - lock.unlock(); - } - return; - } - final boolean isAutoCommit = holder.isUnderlyingAutoCommit(); final boolean isReadOnly = holder.isUnderlyingReadOnly(); @@ -810,9 +798,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat holder.reset(); if (isTestOnReturn()) { - boolean validate = testConnectionInternal(conn); + boolean validate = testConnectionInternal(physicalConnection); if (!validate) { - JdbcUtils.close(conn); + JdbcUtils.close(physicalConnection); destroyCount.incrementAndGet(); @@ -830,28 +818,21 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat boolean neadDestory = false; lock.lockInterruptibly(); try { - if (holder.getModCount() == this.modCount) { - activeCount--; - closeCount++; + activeCount--; + closeCount++; - // 第六步,加入队列中(putLast) - putLast(holder); - recycleCount++; - } else { - activeCount--; - closeCount++; - neadDestory = true; - } + putLast(holder); + recycleCount++; } finally { lock.unlock(); } if (neadDestory) { destroyCount.incrementAndGet(); - JdbcUtils.close(conn); + JdbcUtils.close(physicalConnection); } } catch (Throwable e) { - JdbcUtils.close(conn); + JdbcUtils.close(physicalConnection); try { lock.lockInterruptibly(); @@ -974,11 +955,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat notEmptyWaitThreadCount--; } notEmptyWaitCount++; - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } } } catch (InterruptedException ie) { notEmpty.signal(); // propagate to non-interrupted thread @@ -1017,11 +993,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat // creator notEmptyWaitCount++; notEmptyWaitNanos += (startEstimate - estimate); - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } } catch (InterruptedException ie) { notEmpty.signal(); // propagate to non-interrupted thread notEmptySignalCount++; @@ -1310,10 +1281,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return removeCount; } - public DataSourceProxyConfig getConfig() { - return null; - } - /** Instance key */ protected String instanceKey = null; @@ -1327,22 +1294,15 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat static class ActiveConnectionTraceInfo { - private final DruidPooledConnection connection; - private final long connectTime; - private final StackTraceElement[] stackTrace; + private final long connectTime; + private final StackTraceElement[] stackTrace; - public ActiveConnectionTraceInfo(DruidPooledConnection connection, long connectTime, - StackTraceElement[] stackTrace){ + public ActiveConnectionTraceInfo(long connectTime, StackTraceElement[] stackTrace){ super(); - this.connection = connection; this.connectTime = connectTime; this.stackTrace = stackTrace; } - public DruidPooledConnection getConnection() { - return connection; - } - public long getConnectTime() { return connectTime; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java index 3fae0030f2..390e04215a 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java +++ b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java @@ -61,7 +61,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec protected TransactionInfo transactionInfo; private final boolean dupCloseLogEnable; private boolean traceEnable = false; - private boolean diable = false; + private boolean disable = false; private boolean closed = false; private final Thread ownerThread; @@ -157,20 +157,20 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec return conn; } - void disable() { + public void disable() { this.traceEnable = false; this.holder = null; this.transactionInfo = null; - this.diable = true; + this.disable = true; } - public boolean isDiable() { - return diable; + public boolean isDisable() { + return disable; } @Override public void close() throws SQLException { - if (this.diable) { + if (this.disable) { return; } @@ -194,16 +194,20 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } else { recycle(); } + + this.disable = true; } public void recycle() throws SQLException { - if (this.diable) { + if (this.disable) { return; } DruidConnectionHolder holder = this.holder; - if (holder == null && dupCloseLogEnable) { - LOG.error("dup close"); + if (holder == null) { + if (dupCloseLogEnable) { + LOG.error("dup close"); + } return; } @@ -972,7 +976,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } public void checkState() throws SQLException { - if (holder == null || closed || diable) { + if (holder == null || closed || disable) { throw new SQLException("connection is closed"); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_clearCache.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_clearCache.java new file mode 100644 index 0000000000..16f04351a2 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_clearCache.java @@ -0,0 +1,52 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; +import java.sql.PreparedStatement; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker; + +/** + * 这个场景测试minIdle > maxActive + * + * @author wenshao + */ +public class DruidDataSourceTest_clearCache extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setPoolPreparedStatements(true); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_clearStatementCache() throws Exception { + { + Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement("select 1"); + stmt.close(); + conn.close(); + } + { + Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement("select 1, 2"); + stmt.close(); + conn.close(); + } + Assert.assertEquals(2, dataSource.getCachedPreparedStatementCount()); + + dataSource.clearStatementCache(); + + Assert.assertEquals(0, dataSource.getCachedPreparedStatementCount()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_enable.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_enable.java new file mode 100644 index 0000000000..691d1b67e8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_enable.java @@ -0,0 +1,71 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; +import java.sql.PreparedStatement; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DataSourceDisableException; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker; + +/** + * 这个场景测试minIdle > maxActive + * + * @author wenshao + */ +public class DruidDataSourceTest_enable extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setMaxWait(1000); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_disable() throws Exception { + { + Connection conn = dataSource.getConnection(); + conn.close(); + } + Assert.assertTrue(dataSource.isEnable()); + + dataSource.setEnable(false); + + Assert.assertFalse(dataSource.isEnable()); + + dataSource.shrink(); + + Exception error = null; + try { + Connection conn = dataSource.getConnection(); + conn.close(); + } catch (DataSourceDisableException e) { + error = e; + } + Assert.assertNotNull(error); + } + + public void test_disable_() throws Exception { + dataSource.setEnable(false); + + Assert.assertFalse(dataSource.isEnable()); + + Exception error = null; + try { + Connection conn = dataSource.getConnection(); + conn.close(); + } catch (DataSourceDisableException e) { + error = e; + } + Assert.assertNotNull(error); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getConnection.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getConnection.java new file mode 100644 index 0000000000..e081ee69b6 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getConnection.java @@ -0,0 +1,39 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; + +/** + * 这个场景测试defaultAutoCommit + * + * @author wenshao + */ +public class DruidDataSourceTest_getConnection extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_conn_error() throws Exception { + Exception error = null; + try { + dataSource.getConnection(null, null); + } catch (UnsupportedOperationException e) { + error = e; + } + Assert.assertNotNull(error); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getPoolingPeakTime.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getPoolingPeakTime.java index 114c7cb91f..9b121e619d 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getPoolingPeakTime.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_getPoolingPeakTime.java @@ -34,5 +34,6 @@ public class DruidDataSourceTest_getPoolingPeakTime extends TestCase { conn.close(); Assert.assertNotNull(dataSource.getPoolingPeakTime()); + Assert.assertNotNull(dataSource.getActivePeakTime()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_notEmptyWait2.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_notEmptyWait2.java index 2405413fe2..d3577dac40 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_notEmptyWait2.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_notEmptyWait2.java @@ -82,6 +82,7 @@ public class DruidDataSourceTest_notEmptyWait2 extends TestCase { errorThreadEndLatch.await(100, TimeUnit.MILLISECONDS); Assert.assertEquals(1, maxWaitErrorCount.get()); + Assert.assertTrue(dataSource.getNotEmptySignalCount() > 0); conn.close(); diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle.java new file mode 100644 index 0000000000..f7738c05eb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle.java @@ -0,0 +1,41 @@ +package com.alibaba.druid.bvt.pool; + + +import java.sql.Statement; + +import junit.framework.TestCase; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; + +/** + * 这个场景测试initialSize > maxActive + * + * @author wenshao + */ +public class DruidDataSourceTest_recycle extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setMaxActive(1); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_recycle() throws Exception { + DruidPooledConnection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + conn.setReadOnly(false); + + Statement stmt = conn.createStatement(); + stmt.execute("select 1"); + + conn.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle2.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle2.java new file mode 100644 index 0000000000..03d11e07cd --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_recycle2.java @@ -0,0 +1,78 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.Assert; + +import junit.framework.TestCase; + +import com.alibaba.druid.filter.FilterAdapter; +import com.alibaba.druid.filter.FilterChain; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; +import com.alibaba.druid.proxy.jdbc.ConnectionProxy; + +/** + * 这个场景测试initialSize > maxActive + * + * @author wenshao + */ +public class DruidDataSourceTest_recycle2 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.getProxyFilters().add(new FilterAdapter() { + + public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException { + throw new SQLException(); + } + }); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_recycle() throws Exception { + DruidPooledConnection conn = dataSource.getConnection(); + + Statement stmt = conn.createStatement(); + stmt.execute("select 1"); + + Assert.assertEquals(0, dataSource.getPoolingCount()); + Assert.assertEquals(1, dataSource.getActiveCount()); + + conn.close(); + + Assert.assertEquals(1, dataSource.getPoolingCount()); + Assert.assertEquals(0, dataSource.getActiveCount()); + } + + public void test_recycle_error() throws Exception { + DruidPooledConnection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + conn.setReadOnly(false); + + Statement stmt = conn.createStatement(); + stmt.execute("select 1"); + + Assert.assertEquals(0, dataSource.getPoolingCount()); + Assert.assertEquals(1, dataSource.getActiveCount()); + + Exception error = null; + try { + conn.close(); + } catch (Exception e) { + error = e; + } + Assert.assertNotNull(error); + + Assert.assertEquals(0, dataSource.getPoolingCount()); + Assert.assertEquals(0, dataSource.getActiveCount()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidPooledConnectionTest.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidPooledConnectionTest.java new file mode 100644 index 0000000000..57bb8f6b59 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidPooledConnectionTest.java @@ -0,0 +1,83 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; + +public class DruidPooledConnectionTest extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setFilters("stat"); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_rollback() throws Exception { + Connection conn = dataSource.getConnection(); + conn.rollback(); + conn.rollback(null); + + conn.close(); + } + + public void test_rollback_1() throws Exception { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + + conn.close(); + conn.rollback(); + conn.rollback(null); + } + + public void test_getOwnerThread() throws Exception { + DruidPooledConnection conn = (DruidPooledConnection) dataSource.getConnection(); + + Assert.assertEquals(Thread.currentThread(), conn.getOwnerThread()); + + conn.close(); + } + + public void test_isDiable() throws Exception { + DruidPooledConnection conn = (DruidPooledConnection) dataSource.getConnection(); + + Assert.assertEquals(false, conn.isDisable()); + + conn.close(); + + Assert.assertEquals(true, conn.isDisable()); + } + + public void test_dupClose() throws Exception { + DruidPooledConnection conn = (DruidPooledConnection) dataSource.getConnection(); + + conn.close(); + conn.close(); + } + + public void test_disable() throws Exception { + Assert.assertEquals(0, dataSource.getPoolingCount()); + Assert.assertEquals(0, dataSource.getActiveCount()); + + DruidPooledConnection conn = (DruidPooledConnection) dataSource.getConnection(); + conn.disable(); + Assert.assertEquals(true, conn.isDisable()); + + Assert.assertEquals(1, dataSource.getActiveCount()); + + conn.close(); + + Assert.assertEquals(0, dataSource.getPoolingCount()); + Assert.assertEquals(1, dataSource.getActiveCount()); + } +}