diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index e28fe984c1..9cb3a5b955 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -1457,6 +1457,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements public Date getCreatedTime() { return createdTime; } + + public abstract boolean isOracle(); public abstract int getRawDriverMajorVersion(); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 149c25ea24..f9ccfb1f4f 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -108,6 +108,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private String initStackTrace; + private boolean isOracle = false; + public DruidDataSource(){ } @@ -286,6 +288,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat this.dbType = JdbcUtils.getDbType(jdbcUrl, driverClass.getClass().getName()); + if ("oracle".equals(this.dbType)) { + isOracle = true; + } + String realDriverClassName = driver.getClass().getName(); if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { this.validConnectionChecker = new MySqlValidConnectionChecker(); @@ -1314,6 +1320,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + public boolean isOracle() { + return isOracle; + } + @Override public String getVersion() { return VERSION.MajorVersion + "." + VERSION.MinorVersion + "." + VERSION.RevisionVersion + "-2011-12-27 14:45"; diff --git a/src/main/java/com/alibaba/druid/pool/OracleUtils.java b/src/main/java/com/alibaba/druid/pool/OracleUtils.java index 9a0f9883ec..de3ed1affb 100644 --- a/src/main/java/com/alibaba/druid/pool/OracleUtils.java +++ b/src/main/java/com/alibaba/druid/pool/OracleUtils.java @@ -1,17 +1,40 @@ package com.alibaba.druid.pool; +import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import oracle.jdbc.OracleConnection; import oracle.jdbc.driver.OracleStatement; - public class OracleUtils { + public static void clearDefines(PoolablePreparedStatement stmt) throws SQLException { - PreparedStatement raw = stmt.getRawPreparedStatement(); - if (raw instanceof OracleStatement) { - OracleStatement oracleStmt = (OracleStatement) raw; - oracleStmt.clearDefines(); + OracleStatement oracleStmt = stmt.unwrap(OracleStatement.class); + oracleStmt.clearDefines(); + } + + public static int getRowPrefetch(PreparedStatement stmt) throws SQLException { + OracleStatement oracleStmt = stmt.unwrap(OracleStatement.class); + return oracleStmt.getRowPrefetch(); + } + + public static void setRowPrefetch(PreparedStatement stmt, int value) throws SQLException { + OracleStatement oracleStmt = stmt.unwrap(OracleStatement.class); + oracleStmt.setRowPrefetch(value); + } + + public static void setDefaultRowPrefetch(Connection conn, int value) throws SQLException { + OracleConnection oracleConn = conn.unwrap(OracleConnection.class); + oracleConn.setDefaultRowPrefetch(value); + } + + public static int getDefaultRowPrefetch(Connection conn, int value) throws SQLException { + if (conn instanceof OracleConnection) { + OracleConnection oracleConn = (OracleConnection) conn; + return oracleConn.getDefaultRowPrefetch(); } + + return -1; } } diff --git a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java index f6f698bf83..2771f4d6a1 100644 --- a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java +++ b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java @@ -97,8 +97,8 @@ public class PoolableConnection implements PooledConnection, Connection { throw new SQLException("Error", t); } - private boolean isOracle() { - return "oracle".equals(holder.getDataSource().getDbType()); + public boolean isOracle() { + return holder.getDataSource().isOracle(); } void closePoolableStatement(PoolablePreparedStatement stmt) throws SQLException { diff --git a/src/main/java/com/alibaba/druid/pool/PoolablePreparedStatement.java b/src/main/java/com/alibaba/druid/pool/PoolablePreparedStatement.java index 7972191cd0..03667524c2 100644 --- a/src/main/java/com/alibaba/druid/pool/PoolablePreparedStatement.java +++ b/src/main/java/com/alibaba/druid/pool/PoolablePreparedStatement.java @@ -81,7 +81,7 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep public PreparedStatementHolder getPreparedStatementHolder() { return holder; } - + public int getHitCount() { return holder.getHitCount(); } @@ -173,6 +173,8 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep incrementExecuteCount(); transactionRecord(sql); + oracleSetRowPrefetch(); + try { ResultSet rs = stmt.executeQuery(); @@ -427,6 +429,8 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep incrementExecuteCount(); transactionRecord(sql); + oracleSetRowPrefetch(); + try { return stmt.execute(); } catch (Throwable t) { @@ -434,6 +438,43 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep } } + private void oracleSetRowPrefetch() throws SQLException { + if (!conn.isOracle()) { + return; + } + + if (holder.getHitCount() == 0) { + return; + } + + int fetchRowPeak = holder.getFetchRowPeak(); + + if (fetchRowPeak < 0) { + return; + } + + if (holder.getDefaultRowPretch() == -1) { + int defaultRowPretch = OracleUtils.getRowPrefetch(this); + holder.setDefaultRowPretch(defaultRowPretch); + holder.setRowPrefetch(defaultRowPretch); + } + + int rowPrefetch; + + if (fetchRowPeak <= 1) { + rowPrefetch = 1; + } else if (fetchRowPeak > holder.getDefaultRowPretch()) { + rowPrefetch = holder.getDefaultRowPretch(); + } else { + rowPrefetch = fetchRowPeak; + } + + if (rowPrefetch != holder.getRowPrefetch()) { + OracleUtils.setRowPrefetch(this, rowPrefetch); + holder.setRowPrefetch(rowPrefetch); + } + } + @Override public void addBatch() throws SQLException { checkOpen(); diff --git a/src/main/java/com/alibaba/druid/pool/PoolableWrapper.java b/src/main/java/com/alibaba/druid/pool/PoolableWrapper.java index cd73078fd3..695fd47448 100644 --- a/src/main/java/com/alibaba/druid/pool/PoolableWrapper.java +++ b/src/main/java/com/alibaba/druid/pool/PoolableWrapper.java @@ -35,6 +35,10 @@ public class PoolableWrapper implements Wrapper { return false; } + if (iface.isInstance(wrapper)) { + return true; + } + if (iface.isInstance(this)) { return true; } @@ -49,6 +53,10 @@ public class PoolableWrapper implements Wrapper { return null; } + if (iface.isInstance(wrapper)) { + return (T) wrapper; + } + if (iface.isInstance(this)) { return (T) this; } diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java index bf5bf53f9d..6b37f3b39a 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementHolder.java @@ -26,15 +26,34 @@ public final class PreparedStatementHolder { private final PreparedStatementKey key; private final PreparedStatement statement; - private int hitCount = 0; + private int hitCount = 0; - private int fetchRowPeak = -1; + private int fetchRowPeak = -1; + + private int defaultRowPretch = -1; + private int rowPrefetch = -1; public PreparedStatementHolder(PreparedStatementKey key, PreparedStatement stmt){ this.key = key; this.statement = stmt; } + public int getDefaultRowPretch() { + return defaultRowPretch; + } + + public void setDefaultRowPretch(int defaultRowPretch) { + this.defaultRowPretch = defaultRowPretch; + } + + public int getRowPrefetch() { + return rowPrefetch; + } + + public void setRowPrefetch(int rowPrefetch) { + this.rowPrefetch = rowPrefetch; + } + public int getFetchRowPeak() { return fetchRowPeak; } diff --git a/src/test/java/com/alibaba/druid/pool/TestDruidOraclePreparedStatement.java b/src/test/java/com/alibaba/druid/pool/TestDruidOraclePreparedStatement.java new file mode 100644 index 0000000000..722c3c1a16 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/TestDruidOraclePreparedStatement.java @@ -0,0 +1,84 @@ +package com.alibaba.druid.pool; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import junit.framework.TestCase; +import oracle.jdbc.OracleConnection; +import oracle.jdbc.driver.OraclePreparedStatement; + +import com.alibaba.druid.util.JdbcUtils; + +public class TestDruidOraclePreparedStatement extends TestCase { + + private String jdbcUrl; + private String user; + private String password; + + private DruidDataSource dataSource; + + public void setUp() throws Exception { + jdbcUrl = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; + // jdbcUrl = "jdbc:oracle:thin:@20.20.149.85:1521:ocnauto"; // error url + user = "alibaba"; + password = "ccbuauto"; + + dataSource = new DruidDataSource(); + dataSource.setPoolPreparedStatements(true); + + dataSource.setUrl(jdbcUrl); + dataSource.setUsername(user); + dataSource.setPassword(password); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_0() throws Exception { + + Class.forName(JdbcUtils.getDriverClassName(jdbcUrl)); + + for (int i = 0; i < 3; ++i) { + Connection conn = dataSource.getConnection(); + + // ResultSet metaRs = conn.getMetaData().getTables(null, "ALIBABA", null, new String[] {"TABLE"}); + // JdbcUtils.printResultSet(metaRs); + // metaRs.close(); + + String sql = "SELECT * FROM WS_OFFER WHERE ROWNUM <= ?"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, 1); + ResultSet rs = stmt.executeQuery(); + while (rs.next()) { + + } + + rs.close(); + stmt.close(); + conn.close(); + } + { + Connection conn = dataSource.getConnection(); + + // ResultSet metaRs = conn.getMetaData().getTables(null, "ALIBABA", null, new String[] {"TABLE"}); + // JdbcUtils.printResultSet(metaRs); + // metaRs.close(); + + String sql = "SELECT * FROM WS_OFFER WHERE ROWNUM <= ?"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, 11); + ResultSet rs = stmt.executeQuery(); + rs.next(); + + rs.close(); + stmt.close(); + conn.close(); + } + + } +} diff --git a/src/test/java/com/alibaba/druid/pool/TestOraclePreparedStatement.java b/src/test/java/com/alibaba/druid/pool/TestOraclePreparedStatement.java index 65f5b6d7a7..745cd949f8 100644 --- a/src/test/java/com/alibaba/druid/pool/TestOraclePreparedStatement.java +++ b/src/test/java/com/alibaba/druid/pool/TestOraclePreparedStatement.java @@ -6,6 +6,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import junit.framework.TestCase; +import oracle.jdbc.OracleConnection; import oracle.jdbc.driver.OraclePreparedStatement; import com.alibaba.druid.util.JdbcUtils; @@ -28,10 +29,14 @@ public class TestOraclePreparedStatement extends TestCase { Connection conn = DriverManager.getConnection(jdbcUrl, user, password); + OracleConnection oracleConn = (OracleConnection) conn; + // ResultSet metaRs = conn.getMetaData().getTables(null, "ALIBABA", null, new String[] {"TABLE"}); // JdbcUtils.printResultSet(metaRs); // metaRs.close(); - + + int fetchRowSize = oracleConn.getDefaultRowPrefetch(); + String sql = "SELECT * FROM WS_OFFER WHERE ROWNUM <= ?"; OraclePreparedStatement oracleStmt = null; @@ -39,15 +44,15 @@ public class TestOraclePreparedStatement extends TestCase { oracleStmt = (OraclePreparedStatement) stmt; oracleStmt.setRowPrefetch(1); { - + stmt.setInt(1, 1); ResultSet rs = stmt.executeQuery(); while (rs.next()) { - + } rs.close(); - + oracleStmt.clearDefines(); } oracleStmt.setRowPrefetch(1000); @@ -55,7 +60,7 @@ public class TestOraclePreparedStatement extends TestCase { stmt.setInt(1, 11); ResultSet rs = stmt.executeQuery(); rs.next(); - + rs.close(); stmt.close(); }