diff --git a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java index 16b0866231..c6c619df53 100644 --- a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java +++ b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java @@ -151,19 +151,7 @@ public final class ConnectionHolder { } public boolean isPoolPreparedStatements() { - // if (dataSource.isOracle()) { - // return false; - // } - - boolean poolPreparedStatements = dataSource.isPoolPreparedStatements(); - if (poolPreparedStatements) { - boolean transaction = !isUnderlyingAutoCommit(); - if (transaction && !dataSource.isSharePreparedStatements()) { - poolPreparedStatements = false; - } - } - - return poolPreparedStatements; + return dataSource.isPoolPreparedStatements(); } public Connection getConnection() { diff --git a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java index 14df872e49..dd39ccb42a 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java +++ b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java @@ -118,6 +118,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec return; } + stmt.getPreparedStatementHolder().decrementInUseCount(); if (holder.isPoolPreparedStatements()) { holder.getStatementPool().put(stmt.getPreparedStatementHolder()); @@ -202,7 +203,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -210,6 +211,11 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec return rtnVal; } + + private void initStatement(PreparedStatementHolder stmtHolder) throws SQLException { + stmtHolder.incrementInUseCount(); + holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) @@ -236,7 +242,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -271,7 +277,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -302,7 +308,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -333,7 +339,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -364,7 +370,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); @@ -397,7 +403,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); @@ -432,7 +438,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); @@ -465,7 +471,7 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec } } - holder.getDataSource().initStatement(this, stmtHolder.getStatement()); + initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java index 761f1ffbc5..2891cb427c 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java @@ -35,6 +35,8 @@ public final class PreparedStatementHolder { private boolean enterOracleImplicitCache = false; + private int inUseCount = 0; + public PreparedStatementHolder(PreparedStatementKey key, PreparedStatement stmt){ this.key = key; this.statement = stmt; @@ -90,4 +92,19 @@ public final class PreparedStatementHolder { return hitCount; } + public boolean isInUse() { + return inUseCount <= 0; + } + + public void incrementInUseCount() { + inUseCount++; + } + + public void decrementInUseCount() { + inUseCount--; + } + + public int getInUseCount() { + return inUseCount; + } } diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java index ff1af01eb8..e826aecaf3 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java @@ -54,7 +54,10 @@ public class PreparedStatementPool { PreparedStatementHolder holder = map.get(key); if (holder != null) { - holder.incrementHitCount(); + if (holder.isInUse() && (!dataSource.isSharePreparedStatements())) { + return null; + } + dataSource.incrementCachedPreparedStatementHitCount(); if (holder.isEnterOracleImplicitCache()) { OracleUtils.exitImplicitCacheToActive(holder.getStatement()); diff --git a/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest.java b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest.java new file mode 100644 index 0000000000..916422c170 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest.java @@ -0,0 +1,81 @@ +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.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledPreparedStatement; +import com.alibaba.druid.util.JdbcUtils; + +public class PSCacheTest extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:x1"); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxOpenPreparedStatements(10); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_noTxn() throws Exception { + Connection conn = dataSource.getConnection(); + + String sql = "select 1"; + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + stmt0.close(); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertEquals(1, pooledStmt1.getPreparedStatementHolder().getInUseCount()); + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt0.getPreparedStatementHolder()); // same + + PreparedStatement stmt2 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt2 = (DruidPooledPreparedStatement) stmt2; + + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt2.getPreparedStatementHolder()); // not same + + stmt1.close(); + stmt2.close(); + + conn.close(); + } + + public void test_txn() throws Exception { + Connection conn = dataSource.getConnection(); + + conn.setAutoCommit(false); + + String sql = "select 1"; + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + stmt0.close(); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertEquals(1, pooledStmt1.getPreparedStatementHolder().getInUseCount()); + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt0.getPreparedStatementHolder()); // same + + PreparedStatement stmt2 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt2 = (DruidPooledPreparedStatement) stmt2; + + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt2.getPreparedStatementHolder()); // not same + + stmt1.close(); + stmt2.close(); + + conn.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest1.java b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest1.java new file mode 100644 index 0000000000..d501592f21 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest1.java @@ -0,0 +1,83 @@ +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.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledPreparedStatement; +import com.alibaba.druid.util.JdbcUtils; + +public class PSCacheTest1 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:x1"); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxOpenPreparedStatements(10); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_noTxn() throws Exception { + { + Connection conn = dataSource.getConnection(); + + String sql = "select 1"; + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + stmt0.close(); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertEquals(1, pooledStmt1.getPreparedStatementHolder().getInUseCount()); + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt0.getPreparedStatementHolder()); // same + + PreparedStatement stmt2 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt2 = (DruidPooledPreparedStatement) stmt2; + + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt2.getPreparedStatementHolder()); // not + // same + + conn.close(); + } + { + Connection conn = dataSource.getConnection(); + + conn.setAutoCommit(false); + + String sql = "select 1"; + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + stmt0.close(); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertEquals(1, pooledStmt1.getPreparedStatementHolder().getInUseCount()); + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt0.getPreparedStatementHolder()); // same + + PreparedStatement stmt2 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt2 = (DruidPooledPreparedStatement) stmt2; + + Assert.assertNotSame(pooledStmt1.getPreparedStatementHolder(), pooledStmt2.getPreparedStatementHolder()); // not + // same + + stmt1.close(); + stmt2.close(); + + conn.close(); + } + } + + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest2.java b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest2.java new file mode 100644 index 0000000000..452dc10dab --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest2.java @@ -0,0 +1,82 @@ +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.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledPreparedStatement; +import com.alibaba.druid.util.JdbcUtils; + +public class PSCacheTest2 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:x1"); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxOpenPreparedStatements(10); + dataSource.setSharePreparedStatements(true); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_0() throws Exception { + Connection conn = dataSource.getConnection(); + + String sql = "select 1"; + + { + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.close(); + } + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + + Assert.assertEquals(1, pooledStmt0.getPreparedStatementHolder().getInUseCount()); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertSame(pooledStmt0.getPreparedStatementHolder(), pooledStmt1.getPreparedStatementHolder()); + + stmt0.close(); + stmt1.close(); + + conn.close(); + } + + public void test_txn() throws Exception { + Connection conn = dataSource.getConnection(); + + conn.setAutoCommit(true); + + String sql = "select 1"; + + { + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.close(); + } + + PreparedStatement stmt0 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt0 = (DruidPooledPreparedStatement) stmt0; + + Assert.assertEquals(1, pooledStmt0.getPreparedStatementHolder().getInUseCount()); + + PreparedStatement stmt1 = conn.prepareStatement(sql); + DruidPooledPreparedStatement pooledStmt1 = (DruidPooledPreparedStatement) stmt1; + + Assert.assertSame(pooledStmt0.getPreparedStatementHolder(), pooledStmt1.getPreparedStatementHolder()); + + stmt0.close(); + stmt1.close(); + + conn.close(); + } +}