diff --git a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java index 2dcdc310e3..677239b08c 100644 --- a/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java +++ b/src/main/java/com/alibaba/druid/pool/ConnectionHolder.java @@ -66,7 +66,7 @@ public final class ConnectionHolder { this.defaultHoldability = conn.getHoldability(); this.defaultTransactionIsolation = conn.getTransactionIsolation(); this.defaultAutoCommit = conn.getAutoCommit(); - + this.underlyingAutoCommit = defaultAutoCommit; this.underlyingHoldability = defaultHoldability; this.underlyingTransactionIsolation = defaultTransactionIsolation; @@ -143,7 +143,15 @@ public final class ConnectionHolder { } public boolean isPoolPreparedStatements() { - return dataSource.isPoolPreparedStatements(); + boolean poolPreparedStatements = dataSource.isPoolPreparedStatements(); + if (poolPreparedStatements) { + boolean transaction = !isUnderlyingAutoCommit(); + if (transaction && !dataSource.isSharePreparedStatements()) { + poolPreparedStatements = false; + } + } + + return poolPreparedStatements; } public Connection getConnection() { diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index b6bba26a18..594276a113 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -119,6 +119,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; private boolean testWhileIdle = DEFAULT_WHILE_IDLE; protected boolean poolPreparedStatements = false; + protected boolean sharePreparedStatements = false; protected int maxPoolPreparedStatementPerConnectionSize = 10; protected boolean inited = false; @@ -206,7 +207,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements if (transactionQueryTimeout <= 0) { return queryTimeout; } - + return transactionQueryTimeout; } @@ -349,9 +350,21 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) { + if (maxPoolPreparedStatementPerConnectionSize > 0) { + this.poolPreparedStatements = true; + } + this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; } + public boolean isSharePreparedStatements() { + return sharePreparedStatements; + } + + public void setSharePreparedStatements(boolean sharePreparedStatements) { + this.sharePreparedStatements = sharePreparedStatements; + } + public void incrementDupCloseCount() { dupCloseCount.incrementAndGet(); } @@ -436,7 +449,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements } public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) { - this.maxPoolPreparedStatementPerConnectionSize = maxOpenPreparedStatements; + this.setMaxPoolPreparedStatementPerConnectionSize(maxOpenPreparedStatements); } public boolean isLogAbandoned() { @@ -1044,9 +1057,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements void initStatement(PoolableConnection conn, Statement stmt) throws SQLException { boolean transaction = !conn.getConnectionHolder().isUnderlyingAutoCommit(); - + int queryTimeout = transaction ? getTransactionQueryTimeout() : getQueryTimeout(); - + if (queryTimeout > 0) { stmt.setQueryTimeout(queryTimeout); } diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java index 3168e11ba6..8a3c55cf8a 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java @@ -44,7 +44,7 @@ public interface DruidAbstractDataSourceMBean { long getStartTransactionCount(); int getQueryTimeout(); - + int getTransactionQueryTimeout(); String getValidationQuery(); @@ -66,13 +66,13 @@ public interface DruidAbstractDataSourceMBean { List getFilterClassNames(); boolean isTestOnBorrow(); - + void setTestOnBorrow(boolean testOnBorrow); boolean isTestOnReturn(); - + boolean isTestWhileIdle(); - + void setTestWhileIdle(boolean testWhileIdle); boolean isDefaultAutoCommit(); @@ -85,6 +85,8 @@ public interface DruidAbstractDataSourceMBean { boolean isPoolPreparedStatements(); + boolean isSharePreparedStatements(); + long getMaxWait(); int getMinIdle(); @@ -102,7 +104,7 @@ public interface DruidAbstractDataSourceMBean { long getRemoveAbandonedCount(); boolean isLogAbandoned(); - + void setLogAbandoned(boolean logAbandoned); long getDupCloseCount(); diff --git a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java index 29cf033167..27be537b34 100644 --- a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java +++ b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java @@ -167,11 +167,12 @@ public class PoolableConnection implements PooledConnection, Connection { public PreparedStatement prepareStatement(String sql) throws SQLException { checkOpen(); + PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1); - PreparedStatementHolder stmtHolder = null; + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -179,7 +180,7 @@ public class PoolableConnection implements PooledConnection, Connection { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -203,12 +204,13 @@ public class PoolableConnection implements PooledConnection, Connection { throws SQLException { checkOpen(); + PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M2, resultSetType, resultSetConcurrency); - PreparedStatementHolder stmtHolder = null; + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -217,7 +219,7 @@ public class PoolableConnection implements PooledConnection, Connection { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -241,12 +243,13 @@ public class PoolableConnection implements PooledConnection, Connection { int resultSetHoldability) throws SQLException { checkOpen(); + PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M3, resultSetType, resultSetConcurrency, resultSetHoldability); - PreparedStatementHolder stmtHolder = null; + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -256,7 +259,7 @@ public class PoolableConnection implements PooledConnection, Connection { resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -279,10 +282,12 @@ public class PoolableConnection implements PooledConnection, Connection { public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { checkOpen(); + PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes); PreparedStatementHolder stmtHolder = null; - PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes); - if (holder.isPoolPreparedStatements()) { + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); + + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -290,7 +295,7 @@ public class PoolableConnection implements PooledConnection, Connection { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -313,10 +318,12 @@ public class PoolableConnection implements PooledConnection, Connection { public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { checkOpen(); + PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames); PreparedStatementHolder stmtHolder = null; - PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames); - if (holder.isPoolPreparedStatements()) { + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); + + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -324,7 +331,7 @@ public class PoolableConnection implements PooledConnection, Connection { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -347,10 +354,12 @@ public class PoolableConnection implements PooledConnection, Connection { public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { checkOpen(); + PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys); PreparedStatementHolder stmtHolder = null; - PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys); - if (holder.isPoolPreparedStatements()) { + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); + + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -358,7 +367,7 @@ public class PoolableConnection implements PooledConnection, Connection { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -383,11 +392,12 @@ public class PoolableConnection implements PooledConnection, Connection { public CallableStatement prepareCall(String sql) throws SQLException { checkOpen(); + PreparedStatementHolder stmtHolder = null; PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1); - PreparedStatementHolder stmtHolder = null; + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -395,7 +405,7 @@ public class PoolableConnection implements PooledConnection, Connection { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -420,10 +430,12 @@ public class PoolableConnection implements PooledConnection, Connection { checkOpen(); PreparedStatementHolder stmtHolder = null; - PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_2, resultSetType, resultSetConcurrency, resultSetHoldability); - if (holder.isPoolPreparedStatements()) { + + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); + + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -433,7 +445,7 @@ public class PoolableConnection implements PooledConnection, Connection { resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { @@ -457,10 +469,12 @@ public class PoolableConnection implements PooledConnection, Connection { checkOpen(); PreparedStatementHolder stmtHolder = null; - PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_3, resultSetType, resultSetConcurrency); - if (holder.isPoolPreparedStatements()) { + + boolean poolPreparedStatements = holder.isPoolPreparedStatements(); + + if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } @@ -469,7 +483,7 @@ public class PoolableConnection implements PooledConnection, Connection { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); - if (holder.isPoolPreparedStatements()) { + if (poolPreparedStatements) { holder.getStatementPool().put(stmtHolder); } } catch (SQLException ex) { diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestSharePreparedStatements.java b/src/test/java/com/alibaba/druid/bvt/pool/TestSharePreparedStatements.java new file mode 100644 index 0000000000..e27e2cfc60 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestSharePreparedStatements.java @@ -0,0 +1,91 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.mock.MockPreparedStatement; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.stat.DruidDataSourceStatManager; + +public class TestSharePreparedStatements extends TestCase { + + protected void setUp() throws Exception { + Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size()); + } + + protected void tearDown() throws Exception { + Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size()); + } + + public void test_sharePreparedStatements() throws Exception { + + // sharePreparedStatements + + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(30); + + String sql = "SELECT 1"; + + MockPreparedStatement mockStmt = null; + { + Connection conn = dataSource.getConnection(); + + PreparedStatement stmt = conn.prepareStatement(sql); + mockStmt = stmt.unwrap(MockPreparedStatement.class); + ResultSet rs = stmt.executeQuery(); + rs.next(); + rs.close(); + stmt.close(); + + conn.close(); + } + + { + Connection conn = dataSource.getConnection(); + + PreparedStatement stmt = conn.prepareStatement(sql); + Assert.assertEquals(mockStmt, stmt.unwrap(MockPreparedStatement.class)); + ResultSet rs = stmt.executeQuery(); + rs.next(); + rs.close(); + stmt.close(); + + conn.close(); + } + + { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + + PreparedStatement stmt = conn.prepareStatement(sql); + Assert.assertEquals(true, mockStmt != stmt.unwrap(MockPreparedStatement.class)); + ResultSet rs = stmt.executeQuery(); + rs.next(); + rs.close(); + stmt.close(); + + conn.close(); + } + + { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + + PreparedStatement stmt = conn.prepareStatement(sql); + Assert.assertEquals(true, mockStmt != stmt.unwrap(MockPreparedStatement.class)); + ResultSet rs = stmt.executeQuery(); + rs.next(); + rs.close(); + stmt.close(); + + conn.close(); + } + + dataSource.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/sql/parser/PerfTest.java b/src/test/java/com/alibaba/druid/sql/parser/PerfTest.java index 8893e72e69..f0994b967f 100644 --- a/src/test/java/com/alibaba/druid/sql/parser/PerfTest.java +++ b/src/test/java/com/alibaba/druid/sql/parser/PerfTest.java @@ -19,8 +19,8 @@ public class PerfTest extends TestCase { public void test_perf() throws Exception { for (int i = 0; i < 10; ++i) { // perf("SELECT * FROM my_table WHERE TRUNC(SYSDATE) = DATE '2002-10-03';"); - perfOracle("SELECT * FROM T"); - perfMySql("SELECT * FROM T"); + perfOracle("SELECT a.ID, a.GMT_CREATE, a.GMT_MODIFIED, a.COMPANY_NAME, a.BIZ_TYPE , b.SERVICE_TYPE, b.SERVICE_LEVEL, b.BUSINESS_ROLE, a.STATUS, a.RECOMMENDED , a.COUNTRY, a.PROVINCE, a.CITY, a.ADDRESS, a.ZIP , a.LOGO_FILE, a.EMAIL, a.BRIEF_PROFILE, a.DOMAIN_ID, a.IS_PASS_AV , a.KEYWORDS, a.PROVIDE_PRODUCTS, a.PURCHASE_PRODUCTS, a.BRAND_NAME, a.PROMOTION_VALUE , a.OWNER_MEMBER_ID, a.OWNER_SEQ, a.EMPLOYEES_COUNT, a.ANNUAL_REVENUE, a.HOMEPAGE_URL , a.REG_ADDRESS, a.TRADE_REGION, a.TRADE_REGION_USER, a.REG_CAPITAL, a.OWNERSHIP_TYPE , a.ESTABLISHED_YEAR, a.PRINCIPAL, a.ANNUAL_PURCHASE, a.CERTIFICATION, a.CERTIFICATION_2 , a.CONTACT_MANUFACTURING, a.YEARS_OEM, b.STAGE, a.VIDEO_PATH, a.ABOUTUS_IMAGE_PATH , a.ABOUTUS_IMAGE_TITLE, a.CHINESE_NAME, a.IMAGE_VERSION FROM COMPANY a, VACCOUNT b WHERE a.ID = b.ID AND a.id IN (?)"); + perfMySql("SELECT a.ID, a.GMT_CREATE, a.GMT_MODIFIED, a.COMPANY_NAME, a.BIZ_TYPE , b.SERVICE_TYPE, b.SERVICE_LEVEL, b.BUSINESS_ROLE, a.STATUS, a.RECOMMENDED , a.COUNTRY, a.PROVINCE, a.CITY, a.ADDRESS, a.ZIP , a.LOGO_FILE, a.EMAIL, a.BRIEF_PROFILE, a.DOMAIN_ID, a.IS_PASS_AV , a.KEYWORDS, a.PROVIDE_PRODUCTS, a.PURCHASE_PRODUCTS, a.BRAND_NAME, a.PROMOTION_VALUE , a.OWNER_MEMBER_ID, a.OWNER_SEQ, a.EMPLOYEES_COUNT, a.ANNUAL_REVENUE, a.HOMEPAGE_URL , a.REG_ADDRESS, a.TRADE_REGION, a.TRADE_REGION_USER, a.REG_CAPITAL, a.OWNERSHIP_TYPE , a.ESTABLISHED_YEAR, a.PRINCIPAL, a.ANNUAL_PURCHASE, a.CERTIFICATION, a.CERTIFICATION_2 , a.CONTACT_MANUFACTURING, a.YEARS_OEM, b.STAGE, a.VIDEO_PATH, a.ABOUTUS_IMAGE_PATH , a.ABOUTUS_IMAGE_TITLE, a.CHINESE_NAME, a.IMAGE_VERSION FROM COMPANY a, VACCOUNT b WHERE a.ID = b.ID AND a.id IN (?)"); // perf(loadSql("bvt/parser/oracle-23.txt")); } }