仿照JBOSS实现PreparedStatementCache

git-svn-id: http://code.alibabatech.com/svn/druid/trunk@912 b9813039-fb51-4c41-a8b9-e21c2acb5095
This commit is contained in:
wenshao
2011-09-28 14:20:00 +00:00
parent a7f4299a4b
commit 9dff400ff6
16 changed files with 832 additions and 205 deletions
@@ -67,11 +67,11 @@ public final class ConnectionHolder {
this.lastActiveTimeMillis = lastActiveMillis;
}
public void addTrace(Statement stmt) {
public void addTrace(PoolableStatement stmt) {
statementTrace.add(stmt);
}
public void removeTrace(Statement stmt) {
public void removeTrace(PoolableStatement stmt) {
statementTrace.remove(stmt);
}
@@ -36,7 +36,8 @@ public class PoolableCallableStatement extends PoolablePreparedStatement impleme
private CallableStatement stmt;
public PoolableCallableStatement(PoolableConnection conn, CallableStatement stmt, PreparedStatementKey key, String sql){
public PoolableCallableStatement(PoolableConnection conn, CallableStatement stmt, PreparedStatementKey key,
String sql) throws SQLException{
super(conn, stmt, key, sql);
this.stmt = stmt;
}
@@ -30,7 +30,6 @@ import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -128,15 +127,6 @@ public class PoolableConnection implements PooledConnection, Connection {
listener.connectionClosed(new ConnectionEvent(this));
}
PreparedStatementPool statementPool = holder.getStatementPool();
if (statementPool != null) {
for (List<PoolablePreparedStatement> stmtList : statementPool.getMap().values()) {
for (PoolablePreparedStatement stmt : stmtList) {
stmt.close();
}
}
}
holder.reset();
holder.getDataSource().recycle(this);
@@ -153,28 +143,23 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql);
} catch (SQLException ex) {
handleException(ex);
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
}
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -188,28 +173,23 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M2);
PreparedStatement stmt = null;
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = holder.getStatementPool().get(key);
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -222,28 +202,24 @@ public class PoolableConnection implements PooledConnection, Connection {
checkOpen();
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M3);
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} catch (SQLException ex) {
handleException(ex);
if (holder.isPoolPreparedStatements()) {
stmt = holder.getStatementPool().get(key);
}
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -254,28 +230,24 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4);
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = holder.getStatementPool().get(key);
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql, columnIndexes);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql, columnIndexes);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -286,28 +258,24 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5);
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = holder.getStatementPool().get(key);
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql, columnNames);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql, columnNames);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -318,28 +286,24 @@ public class PoolableConnection implements PooledConnection, Connection {
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
checkOpen();
PreparedStatement stmt = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6);
if (holder.isPoolPreparedStatements()) {
PoolablePreparedStatement poolableStatement = holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = holder.getStatementPool().get(key);
}
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql, autoGeneratedKeys);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareStatement(sql, autoGeneratedKeys);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
PreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
PoolablePreparedStatement rtnVal = new PoolablePreparedStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -354,27 +318,23 @@ public class PoolableConnection implements PooledConnection, Connection {
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1);
if (holder.isPoolPreparedStatements()) {
PoolableCallableStatement poolableStatement = (PoolableCallableStatement) holder.getStatementPool().get(key);
CallableStatement stmt = null;
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
if (holder.isPoolPreparedStatements()) {
stmt = (CallableStatement) holder.getStatementPool().get(key);
}
CallableStatement stmt = null;
try {
stmt = conn.prepareCall(sql);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareCall(sql);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
CallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -386,28 +346,24 @@ public class PoolableConnection implements PooledConnection, Connection {
int resultSetHoldability) throws SQLException {
checkOpen();
CallableStatement stmt = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_2);
if (holder.isPoolPreparedStatements()) {
PoolableCallableStatement poolableStatement = (PoolableCallableStatement) holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = (CallableStatement) holder.getStatementPool().get(key);
}
CallableStatement stmt = null;
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
CallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
@@ -418,29 +374,24 @@ public class PoolableConnection implements PooledConnection, Connection {
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
checkOpen();
CallableStatement stmt = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_3);
if (holder.isPoolPreparedStatements()) {
PoolableCallableStatement poolableStatement = (PoolableCallableStatement) holder.getStatementPool().get(key);
if (poolableStatement != null) {
poolableStatement.setPoolableConnection(this);
poolableStatement.setClosed(false);
holder.addTrace(poolableStatement);
return poolableStatement;
}
stmt = (CallableStatement) holder.getStatementPool().get(key);
}
CallableStatement stmt = null;
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency);
} catch (SQLException ex) {
handleException(ex);
if (stmt == null) {
try {
stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency);
} catch (SQLException ex) {
handleException(ex);
}
}
holder.getDataSource().initStatement(stmt);
CallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
PoolableCallableStatement rtnVal = new PoolableCallableStatement(this, stmt, key, sql);
holder.addTrace(rtnVal);
return rtnVal;
@@ -552,14 +503,14 @@ public class PoolableConnection implements PooledConnection, Connection {
handleException(ex);
}
}
protected void transactionRecord(String sql) throws SQLException {
if (transactionInfo == null && (!conn.getAutoCommit())) {
DruidAbstractDataSource dataSource = holder.getDataSource();
dataSource.incrementStartTransactionCount();
transactionInfo = new TransactionInfo(dataSource.createTransactionId());
}
if (transactionInfo != null) {
transactionInfo.getSqlList().add(sql);
}
@@ -597,7 +548,7 @@ public class PoolableConnection implements PooledConnection, Connection {
if (transactionInfo == null) {
return;
}
checkOpen();
DruidAbstractDataSource dataSource = holder.getDataSource();
@@ -643,7 +594,7 @@ public class PoolableConnection implements PooledConnection, Connection {
long transactionMillis = currentTimeMillis - transactionInfo.getStartTimeMillis();
dataSource.getTransactionHistogram().recode(transactionMillis);
dataSource.logTransaction( transactionInfo);
dataSource.logTransaction(transactionInfo);
transactionInfo = null;
}
@@ -47,12 +47,60 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
private final PreparedStatementKey key;
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;
public PoolablePreparedStatement(PoolableConnection conn, PreparedStatement stmt, PreparedStatementKey key,
String sql){
String sql) throws SQLException{
super(conn, stmt);
this.stmt = stmt;
this.key = key;
this.sql = sql;
// Remember the defaults
defaultMaxFieldSize = stmt.getMaxFieldSize();
defaultMaxRows = stmt.getMaxRows();
defaultQueryTimeout = stmt.getQueryTimeout();
defaultFetchDirection = stmt.getFetchDirection();
defaultFetchSize = stmt.getFetchSize();
currentMaxFieldSize = defaultMaxFieldSize;
currentMaxRows = defaultMaxRows;
currentQueryTimeout = defaultQueryTimeout;
currentFetchDirection = defaultFetchDirection;
currentFetchSize = defaultFetchSize;
}
public void setFetchSize(int rows) throws SQLException {
currentFetchSize = rows;
super.setFetchSize(rows);
}
public void setFetchDirection(int direction) throws SQLException {
currentFetchDirection = direction;
super.setFetchDirection(direction);
}
public void setMaxFieldSize(int max) throws SQLException {
currentMaxFieldSize = max;
super.setMaxFieldSize(max);
}
public void setMaxRows(int max) throws SQLException {
currentMaxRows = max;
super.setMaxRows(max);
}
public void setQueryTimeout(int seconds) throws SQLException {
currentQueryTimeout = seconds;
super.setQueryTimeout(seconds);
}
public String getSql() {
@@ -77,6 +125,28 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
return;
}
// Reset the defaults
if (defaultMaxFieldSize != currentMaxFieldSize) {
stmt.setMaxFieldSize(defaultMaxFieldSize);
currentMaxFieldSize = defaultMaxFieldSize;
}
if (defaultMaxRows != currentMaxRows) {
stmt.setMaxRows(defaultMaxRows);
currentMaxRows = defaultMaxRows;
}
if (defaultQueryTimeout != currentQueryTimeout) {
stmt.setQueryTimeout(defaultQueryTimeout);
currentQueryTimeout = defaultQueryTimeout;
}
if (defaultFetchDirection != currentFetchDirection) {
stmt.setFetchDirection(defaultFetchDirection);
currentFetchDirection = defaultFetchDirection;
}
if (defaultFetchSize != currentFetchSize) {
stmt.setFetchSize(defaultFetchSize);
currentFetchSize = defaultFetchSize;
}
conn.closePoolableStatement(this);
}
@@ -91,7 +161,7 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
@Override
public ResultSet executeQuery() throws SQLException {
checkOpen();
transactionRecord(sql);
try {
@@ -109,7 +179,7 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
@Override
public int executeUpdate() throws SQLException {
checkOpen();
transactionRecord(sql);
try {
@@ -343,7 +413,7 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
@Override
public boolean execute() throws SQLException {
checkOpen();
transactionRecord(sql);
try {
@@ -363,10 +433,10 @@ public class PoolablePreparedStatement extends PoolableStatement implements Prep
throw checkException(t);
}
}
public int[] executeBatch() throws SQLException {
transactionRecord(sql);
return super.executeBatch();
}
@@ -126,7 +126,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final int getMaxFieldSize() throws SQLException {
public int getMaxFieldSize() throws SQLException {
checkOpen();
try {
@@ -137,7 +137,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final void setMaxFieldSize(int max) throws SQLException {
public void setMaxFieldSize(int max) throws SQLException {
checkOpen();
try {
@@ -159,7 +159,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final void setMaxRows(int max) throws SQLException {
public void setMaxRows(int max) throws SQLException {
checkOpen();
try {
@@ -192,7 +192,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final void setQueryTimeout(int seconds) throws SQLException {
public void setQueryTimeout(int seconds) throws SQLException {
checkOpen();
try {
@@ -298,7 +298,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final void setFetchDirection(int direction) throws SQLException {
public void setFetchDirection(int direction) throws SQLException {
checkOpen();
try {
@@ -320,7 +320,7 @@ public class PoolableStatement extends PoolableWrapper implements Statement {
}
@Override
public final void setFetchSize(int rows) throws SQLException {
public void setFetchSize(int rows) throws SQLException {
checkOpen();
try {
@@ -15,9 +15,8 @@
*/
package com.alibaba.druid.pool;
import java.util.ArrayList;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.List;
import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
@@ -26,46 +25,22 @@ import com.alibaba.druid.pool.PoolablePreparedStatement.PreparedStatementKey;
*/
public class PreparedStatementPool {
private HashMap<PreparedStatementKey, List<PoolablePreparedStatement>> map = new HashMap<PreparedStatementKey, List<PoolablePreparedStatement>>();
private HashMap<PreparedStatementKey, PreparedStatement> map = new HashMap<PreparedStatementKey, PreparedStatement>();
public static enum MethodType {
M1, M2, M3, M4, M5, M6, Precall_1, Precall_2, Precall_3
}
public PoolablePreparedStatement get(PreparedStatementKey key) {
List<PoolablePreparedStatement> list = map.get(key);
if (list == null) {
list = new ArrayList<PoolablePreparedStatement>();
map.put(key, list);
return null;
}
int size = list.size();
if (size == 0) {
return null;
}
PoolablePreparedStatement last = list.remove(size - 1);
return last;
public PreparedStatement get(PreparedStatementKey key) {
return map.remove(key);
}
public void put(PoolablePreparedStatement poolableStatement) {
PreparedStatementKey key = poolableStatement.getKey();
List<PoolablePreparedStatement> list = map.get(key);
if (list == null) {
list = new ArrayList<PoolablePreparedStatement>();
map.put(key, list);
}
list.add(poolableStatement);
map.put(key, poolableStatement.getRawPreparedStatement());
}
public HashMap<PreparedStatementKey, List<PoolablePreparedStatement>> getMap() {
public HashMap<PreparedStatementKey, PreparedStatement> getMap() {
return map;
}
@@ -115,7 +115,7 @@ public class SQLExprParser extends SQLParser {
}
public final SQLExpr multiplicative() throws ParserException {
SQLExpr expr = bitXor();
SQLExpr expr = primary();
return multiplicativeRest(expr);
}
@@ -673,7 +673,7 @@ public class SQLExprParser extends SQLParser {
}
public final SQLExpr equality() throws ParserException {
SQLExpr expr = bitOr();
SQLExpr expr = shift();
return equalityRest(expr);
}
@@ -681,14 +681,14 @@ public class SQLExprParser extends SQLParser {
SQLExpr rightExp;
if (lexer.token() == Token.EQ) {
lexer.nextToken();
rightExp = bitOr();
rightExp = shift();
rightExp = equalityRest(rightExp);
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp);
} else if (lexer.token() == Token.BANGEQ) {
lexer.nextToken();
rightExp = bitOr();
rightExp = shift();
rightExp = equalityRest(rightExp);
@@ -335,7 +335,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.DATE,
SimpleType.STRING, SimpleType.STRING //
, new ArrayType<Long>(1, SimpleType.LONG)
, new ArrayType<Long>(SimpleType.LONG, true)
};
String[] indexNames = {
@@ -368,7 +368,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
"DbType",
"URL" //
, "ExecuteCountHistogram"};
, "Histogram"};
String[] indexDescriptions = indexNames;
COMPOSITE_TYPE = new CompositeType("SqlStatistic", "Sql Statistic", indexNames, indexDescriptions, indexTypes);
@@ -421,7 +421,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
map.put("DbType", dbType);
map.put("URL", null);
map.put("ExecuteCountHistogram", this.histogram.toArray());
map.put("Histogram", this.histogram.toArray());
return map;
}