diff --git a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java index 8386442a34..466dd99149 100644 --- a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java +++ b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java @@ -55,8 +55,11 @@ public final class ConnectionHolder { private int underlyingHoldability; private int underlyingTransactionIsolation; private boolean underlyingAutoCommit; + private final int modCount; public ConnectionHolder(DruidAbstractDataSource dataSource, Connection conn) throws SQLException{ + this.modCount = dataSource.getModCount(); + this.dataSource = dataSource; this.conn = conn; this.connecttimeMillis = System.currentTimeMillis(); @@ -75,6 +78,10 @@ public final class ConnectionHolder { statementPool = null; } + public int getModCount() { + return modCount; + } + public boolean isUnderlyingReadOnly() { return underlyingReadOnly; } @@ -143,10 +150,10 @@ public final class ConnectionHolder { } public boolean isPoolPreparedStatements() { -// if (dataSource.isOracle()) { -// return false; -// } - + // if (dataSource.isOracle()) { + // return false; + // } + boolean poolPreparedStatements = dataSource.isPoolPreparedStatements(); if (poolPreparedStatements) { boolean transaction = !isUnderlyingAutoCommit(); diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 5cd6f352ff..0ab553c0d4 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; import javax.management.JMException; @@ -213,10 +214,18 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements protected boolean useOracleImplicitCache = true; + protected final ReentrantLock lock = new ReentrantLock(); + + protected int modCount = 0; + public boolean isOracle() { return isOracle; } + protected int getModCount() { + return modCount; + } + public void setOracle(boolean isOracle) { if (inited) { throw new IllegalStateException(); @@ -832,11 +841,21 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } public void setUsername(String user) { - if (inited) { - throw new UnsupportedOperationException(); - } + lock.lock(); + try { + if (this.username == user || (this.username != null && this.username.equals(user))) { + return; + } - this.username = user; + if (inited) { + this.modCount++; + clear(); + } + + this.username = user; + } finally { + lock.unlock(); + } } public String getPassword() { @@ -844,11 +863,21 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } public void setPassword(String password) { - if (inited) { - throw new UnsupportedOperationException(); - } + lock.lock(); + try { + if (this.password == password || (this.password != null && this.password.equals(password))) { + return; + } - this.password = password; + if (inited) { + this.modCount++; + clear(); + } + + this.password = password; + } finally { + lock.unlock(); + } } public Properties getConnectProperties() { @@ -901,12 +930,24 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } public void setUrl(String jdbcUrl) { - if (inited) { - throw new UnsupportedOperationException(); - } + lock.lock(); + try { + if (this.jdbcUrl != null && this.jdbcUrl.equals(jdbcUrl)) { + return; + } - this.jdbcUrl = jdbcUrl; + if (inited) { + this.modCount++; + clear(); + } + + this.jdbcUrl = jdbcUrl; + } finally { + lock.unlock(); + } } + + public abstract void clear(); public String getDriverClassName() { return driverClass; diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index ed93101b9f..2adc20f940 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -28,7 +28,6 @@ import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; import javax.naming.NamingException; import javax.naming.Reference; @@ -67,8 +66,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private static final long serialVersionUID = 1L; - private final ReentrantLock lock = new ReentrantLock(); - private final Condition notEmpty = lock.newCondition(); private final Condition empty = lock.newCondition(); @@ -295,7 +292,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat throw new SQLException("not support oracle driver " + driver.getMajorVersion() + "." + driver.getMinorVersion()); } - + if (driver.getMajorVersion() == 10 && isUseOracleImplicitCache()) { this.getConnectProperties().setProperty("oracle.jdbc.FreeMemoryOnEnterImplicitCache", "true"); } @@ -605,17 +602,29 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + boolean neadDestory = false; lock.lockInterruptibly(); try { - activeCount--; - closeCount++; + if (holder.getModCount() == this.modCount) { + activeCount--; + closeCount++; - // 第六步,加入队列中(putLast) - putLast(holder); - recycleCount++; + // 第六步,加入队列中(putLast) + putLast(holder); + recycleCount++; + } else { + destroyCount++; + activeCount--; + closeCount++; + neadDestory = true; + } } finally { lock.unlock(); } + + if (neadDestory) { + JdbcUtils.close(conn); + } } catch (Throwable e) { JdbcUtils.close(conn); @@ -657,7 +666,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (this.closed) { return; } - + if (!this.inited) { return; } @@ -685,9 +694,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat enable = false; notEmpty.signalAll(); notEmptySignalCount++; - + this.closed = true; - + for (Filter filter : filters) { filter.destory(); } @@ -1176,6 +1185,28 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + public void clear() { + final List evictList = new ArrayList(); + + lock.lock(); + try { + for (int i = 0; i < poolingCount; ++i) { + ConnectionHolder connection = connections[i]; + evictList.add(connection); + } + + poolingCount = 0; + } finally { + lock.unlock(); + } + + for (ConnectionHolder item : evictList) { + Connection connection = item.getConnection(); + JdbcUtils.close(connection); + destroyCount++; + } + } + public int getWaitThreadCount() { lock.lock(); try { diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index ca0c5790a4..871242a036 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -46,6 +46,17 @@ public abstract class WallProvider { lock.writeLock().unlock(); } } + + public void clearCache() { + lock.writeLock().lock(); + try { + if (whiteList != null) { + whiteList = null; + } + } finally { + lock.writeLock().unlock(); + } + } public boolean whiteContains(String sql) { lock.readLock().lock(); diff --git a/src/test/java/com/alibaba/druid/benckmark/wall/WallBenchmarkTest.java b/src/test/java/com/alibaba/druid/benckmark/wall/WallBenchmarkTest.java new file mode 100644 index 0000000000..a25ea32b8d --- /dev/null +++ b/src/test/java/com/alibaba/druid/benckmark/wall/WallBenchmarkTest.java @@ -0,0 +1,29 @@ +package com.alibaba.druid.benckmark.wall; + +import junit.framework.TestCase; + +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class WallBenchmarkTest extends TestCase { + + MySqlWallProvider provider = new MySqlWallProvider(); + + public final static int COUNT = 1000 * 1; + + public void test_0() throws Exception { + String sql = "select * from t"; + for (int i = 0; i < 10; ++i) { + provider.clearCache(); + long startMillis = System.currentTimeMillis(); + perf(sql); + long millis = System.currentTimeMillis() - startMillis; + System.out.println("millis : " + millis); + } + } + + public void perf(String sql) { + for (int i = 0; i < COUNT; ++i) { + provider.check(sql + " WHERE FID = " + i); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/basic/DataSourceTest3.java b/src/test/java/com/alibaba/druid/bvt/pool/basic/DataSourceTest3.java index 54301e947d..fa4a860866 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/basic/DataSourceTest3.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/basic/DataSourceTest3.java @@ -1,5 +1,6 @@ package com.alibaba.druid.bvt.pool.basic; +import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; import java.util.Properties; @@ -55,19 +56,32 @@ public class DataSourceTest3 extends TestCase { JdbcStatManager.getInstance().setStatContext(null); } - public void test_prepareStatement_error() throws Exception { - DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); - - conn.close(); + public void test_setUser() throws Exception { + Connection real; { - Exception error = null; - try { - dataSource.setUsername("xxx"); - } catch (Exception ex) { - error = ex; - } - Assert.assertNotNull(error); + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + real = conn.getConnection(); + conn.close(); + } + + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + + dataSource.setUsername(dataSource.getUsername()); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + dataSource.setUsername("xxx_u1"); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertNotSame(real, conn.getConnection()); + conn.close(); } } @@ -159,19 +173,32 @@ public class DataSourceTest3 extends TestCase { } } - public void test_error_7() throws Exception { - DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); - - conn.close(); + public void test_setPassword() throws Exception { + Connection real; { - Exception error = null; - try { - dataSource.setPassword("xx"); - } catch (Exception ex) { - error = ex; - } - Assert.assertNotNull(error); + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + real = conn.getConnection(); + conn.close(); + } + + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + + dataSource.setPassword(dataSource.getPassword()); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + dataSource.setPassword("xxx_pass"); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertNotSame(real, conn.getConnection()); + conn.close(); } } @@ -250,21 +277,32 @@ public class DataSourceTest3 extends TestCase { } } - public void test_error_11() throws Exception { - DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); - - conn.close(); - - dataSource.getUrl(); + public void test_setUrl() throws Exception { + Connection real; { - Exception error = null; - try { - dataSource.setUrl("x"); - } catch (Exception ex) { - error = ex; - } - Assert.assertNotNull(error); + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + real = conn.getConnection(); + conn.close(); + } + + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + + dataSource.setUrl(dataSource.getUrl()); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertSame(real, conn.getConnection()); + conn.close(); + } + dataSource.setUrl("jdbc:mock:xxx_123"); + { + DruidPooledConnection conn = dataSource.getConnection().unwrap(DruidPooledConnection.class); + Assert.assertNotSame(real, conn.getConnection()); + conn.close(); } }