改进PreparedStatementCache

git-svn-id: http://code.alibabatech.com/svn/druid/trunk@916 b9813039-fb51-4c41-a8b9-e21c2acb5095
This commit is contained in:
wenshao
2011-09-29 00:49:34 +00:00
parent 38fcc483f6
commit 0aafc4ab96
10 changed files with 170 additions and 114 deletions
@@ -41,6 +41,7 @@ import com.alibaba.druid.VERSION;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.logging.Log;
import com.alibaba.druid.logging.LogFactory;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
import com.alibaba.druid.pool.vendor.InformixExceptionSorter;
import com.alibaba.druid.pool.vendor.MSSQLValidConnectionChecker;
import com.alibaba.druid.pool.vendor.MockExceptionSorter;
@@ -725,7 +726,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
if (poolingPeakTime <= 0) {
return null;
}
return new Date(poolingPeakTime);
}
@@ -1090,7 +1091,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
lock.unlock();
}
}
public long getErrorCount() {
return this.errorCount.get();
}
@@ -1137,6 +1138,31 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
buf.append("\n}");
if (this.isPoolPreparedStatements()) {
buf.append("\n\n[");
for (int i = 0; i < poolingCount; ++i) {
ConnectionHolder conn = connections[i];
if (conn != null) {
if (i != 0) {
buf.append(",");
}
buf.append("\n\t{ID:");
buf.append(System.identityHashCode(conn));
buf.append(", poolStatements:[");
PreparedStatementPool pool = conn.getStatementPool();
for (Map.Entry<PreparedStatementKey, PreparedStatementHolder> entry : pool.getMap().entrySet()) {
buf.append("\n\t\t{reuseCount:");
buf.append(entry.getValue().getReusedCount());
buf.append(",sql:\"");
buf.append(entry.getKey().getSql());
buf.append("\"");
}
buf.append("}");
}
}
buf.append("\n]");
}
return buf.toString();
}
@@ -37,10 +37,9 @@ public class PoolableCallableStatement extends PoolablePreparedStatement impleme
private CallableStatement stmt;
public PoolableCallableStatement(PoolableConnection conn, CallableStatement stmt, PreparedStatementKey key,
String sql) throws SQLException{
super(conn, stmt, key, sql);
this.stmt = stmt;
public PoolableCallableStatement(PoolableConnection conn, PreparedStatementHolder holder) throws SQLException{
super(conn, holder);
this.stmt = (CallableStatement) holder.getStatement();
}
public CallableStatement getCallableStatementRaw() {
@@ -89,7 +89,7 @@ public class PoolableConnection implements PooledConnection, Connection {
}
if (holder.isPoolPreparedStatements()) {
this.holder.getStatementPool().put(stmt);
this.holder.getStatementPool().put(stmt.getPreparedStatementHolder());
stmt.clearResultSet();
holder.removeTrace(stmt);
stmt.setClosed(true); // soft set close
@@ -110,8 +110,8 @@ public class PoolableConnection implements PooledConnection, Connection {
void closePoolableStatement() {
PreparedStatementPool statmentPool = holder.getStatementPool();
if (statmentPool != null) {
for (PreparedStatement stmt : statmentPool.getMap().values()) {
JdbcUtils.close(stmt);
for (PreparedStatementHolder holder : statmentPool.getMap().values()) {
JdbcUtils.close(holder.getStatement());
}
}
}
@@ -155,15 +155,15 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));
} catch (SQLException ex) {
handleException(ex);
}
@@ -171,9 +171,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -187,15 +187,15 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M2);
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency));
} catch (SQLException ex) {
handleException(ex);
}
@@ -203,9 +203,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -219,15 +219,15 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M3);
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
} catch (SQLException ex) {
handleException(ex);
}
@@ -235,9 +235,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -248,16 +248,16 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4);
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql, columnIndexes);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes));
} catch (SQLException ex) {
handleException(ex);
}
@@ -265,9 +265,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -278,16 +278,16 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5);
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql, columnNames);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames));
} catch (SQLException ex) {
handleException(ex);
}
@@ -295,9 +295,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -308,16 +308,16 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6);
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareStatement(sql, autoGeneratedKeys);
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys));
} catch (SQLException ex) {
handleException(ex);
}
@@ -325,9 +325,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -342,15 +342,15 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1);
CallableStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
if (holder.isPoolPreparedStatements()) {
stmt = (CallableStatement) holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareCall(sql);
stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql));
} catch (SQLException ex) {
handleException(ex);
}
@@ -358,9 +358,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -372,16 +372,16 @@ public class PoolableConnection implements PooledConnection, Connection {
int resultSetHoldability) throws SQLException {
checkOpen();
CallableStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_2);
if (holder.isPoolPreparedStatements()) {
stmt = (CallableStatement) holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
} catch (SQLException ex) {
handleException(ex);
}
@@ -389,9 +389,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmtHolder);
holder.addTrace(rtnVal);
@@ -402,16 +402,16 @@ public class PoolableConnection implements PooledConnection, Connection {
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
checkOpen();
CallableStatement stmt = null;
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_3);
if (holder.isPoolPreparedStatements()) {
stmt = (CallableStatement) holder.getStatementPool().get(key);
stmtHolder = holder.getStatementPool().get(key);
}
if (stmt == null) {
if (stmtHolder == null) {
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency);
stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql, resultSetType, resultSetConcurrency));
} catch (SQLException ex) {
handleException(ex);
}
@@ -419,9 +419,9 @@ public class PoolableConnection implements PooledConnection, Connection {
holder.getDataSource().incrementPreparedStatementCount();
}
holder.getDataSource().initStatement(stmt);
holder.getDataSource().initStatement(stmtHolder.getStatement());
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmtHolder);
holder.addTrace(rtnVal);
return rtnVal;
@@ -43,27 +43,26 @@ import com.alibaba.druid.pool.PreparedStatementPool.MethodType;
*/
public class PoolablePreparedStatement extends PoolableStatement implements PreparedStatement {
private PreparedStatement stmt;
private final PreparedStatementKey key;
private final String sql;
private final PreparedStatementHolder holder;
private final PreparedStatement stmt;
private final String sql;
private int defaultMaxFieldSize;
private int defaultMaxRows;
private int defaultQueryTimeout;
private int defaultFetchDirection;
private int defaultFetchSize;
private int currentMaxFieldSize;
private int currentMaxRows;
private int currentQueryTimeout;
private int currentFetchDirection;
private int currentFetchSize;
private int defaultMaxFieldSize;
private int defaultMaxRows;
private int defaultQueryTimeout;
private int defaultFetchDirection;
private int defaultFetchSize;
private int currentMaxFieldSize;
private int currentMaxRows;
private int currentQueryTimeout;
private int currentFetchDirection;
private int currentFetchSize;
public PoolablePreparedStatement(PoolableConnection conn, PreparedStatement stmt, PreparedStatementKey key,
String sql) throws SQLException{
super(conn, stmt);
this.stmt = stmt;
this.key = key;
this.sql = sql;
public PoolablePreparedStatement(PoolableConnection conn, PreparedStatementHolder holder) throws SQLException{
super(conn, holder.getStatement());
this.stmt = holder.getStatement();
this.holder = holder;
this.sql = holder.getKey().sql;
// Remember the defaults
defaultMaxFieldSize = stmt.getMaxFieldSize();
@@ -77,7 +76,11 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
currentFetchDirection = defaultFetchDirection;
currentFetchSize = defaultFetchSize;
}
public PreparedStatementHolder getPreparedStatementHolder() {
return holder;
}
public void setFetchSize(int rows) throws SQLException {
currentFetchSize = rows;
super.setFetchSize(rows);
@@ -108,7 +111,7 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
}
public PreparedStatementKey getKey() {
return key;
return holder.getKey();
}
public PreparedStatement getRawPreparedStatement() {
@@ -783,8 +786,8 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
public static class PreparedStatementKey {
protected final String sql;
protected final String catalog;
private final String sql;
private final String catalog;
protected final MethodType methodType;
@@ -822,6 +825,10 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
return true;
}
public String getSql() {
return sql;
}
public int hashCode() {
int catalogHashCode = catalog == null ? 0 : catalog.hashCode();
int sqlHashCode = sql.hashCode();
@@ -17,20 +17,36 @@ package com.alibaba.druid.pool;
import java.sql.PreparedStatement;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
/**
* @author wenshao<szujobs@hotmail.com>
*/
public final class PreparedStatementHolder<T extends PreparedStatement> {
public final class PreparedStatementHolder {
private final T statement;
private final PreparedStatementKey key;
private final PreparedStatement statement;
private int useCount = 0;
public PreparedStatementHolder(T stmt){
super();
public PreparedStatementHolder(PreparedStatementKey key, PreparedStatement stmt){
this.key = key;
this.statement = stmt;
}
public T getStatement() {
public PreparedStatement getStatement() {
return statement;
}
public PreparedStatementKey getKey() {
return key;
}
public void incrementReusedCount() {
useCount++;
}
public int getReusedCount() {
return useCount;
}
}
@@ -15,7 +15,8 @@
*/
package com.alibaba.druid.pool;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
import com.alibaba.druid.util.LRUCache;
@@ -25,26 +26,36 @@ import com.alibaba.druid.util.LRUCache;
*/
public class PreparedStatementPool {
private final LRUCache<PreparedStatementKey, PreparedStatement> map;
private final Map<PreparedStatementKey, PreparedStatementHolder> map;
public PreparedStatementPool(int maxSize){
map = new LRUCache<PreparedStatementKey, PreparedStatement>(maxSize);
if (maxSize < 0) {
map = new HashMap<PreparedStatementKey, PreparedStatementHolder>(maxSize);
} else {
map = new LRUCache<PreparedStatementKey, PreparedStatementHolder>(maxSize);
}
}
public static enum MethodType {
M1, M2, M3, M4, M5, M6, Precall_1, Precall_2, Precall_3
}
public PreparedStatement get(PreparedStatementKey key) {
return map.remove(key);
public PreparedStatementHolder get(PreparedStatementKey key) {
PreparedStatementHolder holder = map.remove(key);
if (holder != null) {
holder.incrementReusedCount();
}
return holder;
}
public void put(PoolablePreparedStatement poolableStatement) {
PreparedStatementKey key = poolableStatement.getKey();
map.put(key, poolableStatement.getRawPreparedStatement());
public void put(PreparedStatementHolder holder) {
PreparedStatementKey key = holder.getKey();
map.put(key, holder);
}
public LRUCache<PreparedStatementKey, PreparedStatement> getMap() {
public Map<PreparedStatementKey, PreparedStatementHolder> getMap() {
return map;
}
@@ -76,15 +76,7 @@ public class DataSourceTest3 extends TestCase {
conn.close();
{
Exception error = null;
try {
dataSource.setPoolPreparedStatements(false);
} catch (Exception ex) {
error = ex;
}
Assert.assertNotNull(error);
}
dataSource.setPoolPreparedStatements(false);
}
public void test_error_2() throws Exception {
@@ -18,6 +18,8 @@ import junit.framework.TestCase;
import com.alibaba.druid.mock.MockCallableStatement;
import com.alibaba.druid.pool.PoolableCallableStatement;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
import com.alibaba.druid.pool.PreparedStatementHolder;
public class PoolableCallableStatementTest extends TestCase {
@@ -26,7 +28,7 @@ public class PoolableCallableStatementTest extends TestCase {
protected void setUp() throws Exception {
raw = new MockCallableStatement(null, null);
stmt = new PoolableCallableStatement(null, raw, null, null) {
stmt = new PoolableCallableStatement(null, new PreparedStatementHolder(new PreparedStatementKey("", null, null), raw)) {
protected SQLException checkException(Throwable error) throws SQLException {
if (error instanceof SQLException) {
@@ -14,6 +14,8 @@ import junit.framework.TestCase;
import com.alibaba.druid.mock.MockPreparedStatement;
import com.alibaba.druid.pool.PoolablePreparedStatement;
import com.alibaba.druid.pool.PreparedStatementHolder;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
public class PoolablePreparedStatementTest extends TestCase {
@@ -22,7 +24,7 @@ public class PoolablePreparedStatementTest extends TestCase {
protected void setUp() throws Exception {
raw = new MockPreparedStatement(null, null);
stmt = new PoolablePreparedStatement(null, raw, null, null) {
stmt = new PoolablePreparedStatement(null, new PreparedStatementHolder(new PreparedStatementKey("", null, null), raw)) {
protected SQLException checkException(Throwable error) throws SQLException {
if (error instanceof SQLException) {
@@ -5,8 +5,8 @@ import junit.framework.TestCase;
import org.junit.Assert;
import com.alibaba.druid.mock.MockPreparedStatement;
import com.alibaba.druid.pool.PoolablePreparedStatement;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
import com.alibaba.druid.pool.PreparedStatementHolder;
import com.alibaba.druid.pool.PreparedStatementPool;
import com.alibaba.druid.pool.PreparedStatementPool.MethodType;
@@ -96,8 +96,9 @@ public class PreparedStatementKeyTest extends TestCase {
public void test_contains() throws Exception {
PreparedStatementKey k1 = new PreparedStatementKey("x1", "c1", MethodType.M1);
PreparedStatementPool pool = new PreparedStatementPool();
pool.put(new PoolablePreparedStatement(null, new MockPreparedStatement(null, null), k1, null));
PreparedStatementPool pool = new PreparedStatementPool(10);
MockPreparedStatement raw = new MockPreparedStatement(null, null);
pool.put(new PreparedStatementHolder(k1, raw));
Assert.assertTrue(pool.get(k1) != null);
Assert.assertTrue(pool.get(k1) == null);
}