📄 cacheconnection.java
字号:
/*
DBPool - JDBC Connection Pool Manager
Copyright (c) Giles Winstanley
*/
package snaq.db;
import snaq.util.Reusable;
import java.sql.*;
import java.util.*;
/**
* Connection wrapper that implements statement caching.
* Caching is not performed for statements where additional
* parameters are supplied (ResultSet type/concurrency).
* @see snaq.db.CachedStatement
* @see snaq.db.CachedPreparedStatement
* @see snaq.db.CachedCallableStatement
* @author Giles Winstanley
* @todo Ensure changing caching parameters flushes statements if necessary
*/
public final class CacheConnection implements Connection, StatementListener, Reusable
{
// Constants for determining ResultSet parameters for statements.
private static int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_FORWARD_ONLY;
private static int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;
private static int DEFAULT_RESULTSET_HOLDABILITY = ResultSet.HOLD_CURSORS_OVER_COMMIT;
protected ConnectionPool pool;
protected Connection con;
// Statement cache (List of Statement)
protected List ss = new ArrayList();
protected List ssUsed = new ArrayList();
// PreparedStatement cache (Map of List of PreparedStatement)
protected Map ps = new HashMap();
protected List psUsed = new ArrayList();
// CallableStatement cache (Map of List of CallableStatement)
protected Map cs = new HashMap();
protected List csUsed = new ArrayList();
// Non-cached statements
protected List nonCached = new ArrayList();
// Other variables
private boolean cacheS, cacheP, cacheC;
private int ssReq, ssHit;
private int psReq, psHit;
private int csReq, csHit;
private boolean open = true;
/**
* Creates a new CacheConnection object, using the supplied Connection.
*/
public CacheConnection(ConnectionPool pool, Connection con)
{
this.pool = pool;
this.con = con;
setCacheAll(true);
ssReq = ssHit = psReq = psHit = csReq = csHit = 0;
}
/**
* Added to provide caching support.
*/
void setOpen()
{
open = true;
}
/**
* Added to provide caching support.
*/
boolean isOpen()
{
return open;
}
/**
* Sets whether to use caching for Statements.
*/
public void setCacheStatements(boolean cache)
{
// Release statements if required
if (cacheS && !cache)
{
try { flushSpareStatements(); }
catch (SQLException sqle) { pool.log(sqle); }
}
this.cacheS = cache;
}
/**
* Sets whether to use caching for PreparedStatements.
*/
public void setCachePreparedStatements(boolean cache)
{
// Release statements if required
if (cacheP && !cache)
{
try { flushSparePreparedStatements(); }
catch (SQLException sqle) { pool.log(sqle); }
}
this.cacheP = cache;
}
/**
* Sets whether to use caching for CallableStatements.
*/
public void setCacheCallableStatements(boolean cache)
{
// Release statements if required
if (cacheC && !cache)
{
try { flushSpareCallableStatements(); }
catch (SQLException sqle) { pool.log(sqle); }
}
this.cacheC = cache;
}
/**
* Sets whether to use caching for all types of Statement.
*/
public void setCacheAll(boolean cache)
{
setCacheStatements(cache);
setCachePreparedStatements(cache);
setCacheCallableStatements(cache);
}
/** Returns whether caching of CallableStatements is enabled. */
public boolean isCachingAllStatements() { return cacheS && cacheP && cacheC; }
/** Returns whether caching of CallableStatements is enabled. */
public boolean isCachingStatements() { return cacheS; }
/** Returns whether caching of CallableStatements is enabled. */
public boolean isCachingPreparedStatements() { return cacheP; }
/** Returns whether caching of CallableStatements is enabled. */
public boolean isCachingCallableStatements() { return cacheC; }
/**
* Returns the raw underlying Connection object for which this provides
* a wrapper. This is provided as a convenience method for using database-specific
* features for which the Connection object needs to be upcast.
* (e.g. to use Oracle-specific features needs to be cast to oracle.jdbc.OracleConnection).
* <em>To maintain the stability of the pooling system it is important that the
* raw connection is not destabilized when used in this way.</em>
*/
public Connection getRawConnection()
{
return con;
}
//******************************
// Connection interface methods
//******************************
/** Overrides method to provide caching support. */
public Statement createStatement() throws SQLException
{
return createStatement(DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY);
}
/** Overrides method to provide caching support. */
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
return createStatement(resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY);
}
/** Overrides method to provide caching support. */
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
CachedStatement cs = null;
if (!cacheS)
{
cs = new CachedStatement(con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
cs.setStatementListener(this);
}
else
{
synchronized(ss)
{
ssReq++;
// Find Statement matching criteria required
for (Iterator it = ss.iterator(); it.hasNext();)
{
CachedStatement x = (CachedStatement)it.next();
if (x.getResultSetType() == resultSetType &&
x.getResultSetConcurrency() == resultSetConcurrency &&
x.getResultSetHoldability() == resultSetHoldability)
{
cs = x;
it.remove();
}
}
// Prepare Statement for user
if (cs != null)
{
cs.setOpen();
ssHit++;
if (pool.isDebug())
pool.log("Statement cache hit - " + calcHitRate(ssHit, ssReq));
}
else
{
cs = new CachedStatement(con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
cs.setStatementListener(this);
cs.setOpen();
if (pool.isDebug())
pool.log("Statement cache miss - " + calcHitRate(ssHit, ssReq));
}
}
}
ssUsed.add(cs);
return cs;
}
/** Overrides method to provide caching support. */
public PreparedStatement prepareStatement(String sql) throws SQLException
{
return prepareStatement(sql, DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY);
}
/** Overrides method to provide caching support. */
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return prepareStatement(sql, resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY);
}
/**
* Overrides method to provide caching support.
*/
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
CachedPreparedStatement cps = null;
if (!cacheP)
{
cps = new CachedPreparedStatement(sql, con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
cps.setStatementListener(this);
}
else
{
synchronized(ps)
{
psReq++;
// Get List of cached PreparedStatements with matching SQL
List list = (List)ps.get(sql);
if (list != null)
{
// Find first free PreparedStatement with matching parameters
for (Iterator it = list.iterator(); it.hasNext();)
{
CachedPreparedStatement x = (CachedPreparedStatement)it.next();
if (x.getResultSetType() == resultSetType &&
x.getResultSetConcurrency() == resultSetConcurrency &&
x.getResultSetHoldability() == resultSetHoldability)
{
cps = x;
it.remove();
}
}
}
// Prepare PreparedStatement for user
if (cps != null)
{
cps.setOpen();
psHit++;
if (pool.isDebug())
pool.log("PreparedStatement cache hit [" + sql + "," + cps.getParametersString() + "] - " + calcHitRate(psHit, psReq));
}
else
{
cps = new CachedPreparedStatement(sql, con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
cps.setStatementListener(this);
cps.setOpen();
if (pool.isDebug())
pool.log("PreparedStatement cache miss [" + sql + "," + cps.getParametersString() + "] - " + calcHitRate(psHit, psReq));
}
}
}
psUsed.add(cps);
return cps;
}
/** Overrides method to provide caching support. */
public CallableStatement prepareCall(String sql) throws SQLException
{
return prepareCall(sql, DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY);
}
/** Overrides method to provide caching support. */
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return prepareCall(sql, resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY);
}
/**
* Overrides method to provide caching support.
*/
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
CachedCallableStatement ccs = null;
if (!cacheC)
{
ccs = new CachedCallableStatement(sql, con.prepareCall(sql));
ccs.setStatementListener(this);
}
else
{
synchronized(cs)
{
csReq++;
// Get List of cached CallableStatements with matching SQL
List list = (List)cs.get(sql);
if (list != null)
{
// Find first free CallableStatement with matching parameters
for (Iterator it = list.iterator(); it.hasNext();)
{
CachedCallableStatement x = (CachedCallableStatement)it.next();
if (x.getResultSetType() == resultSetType &&
x.getResultSetConcurrency() == resultSetConcurrency &&
x.getResultSetHoldability() == resultSetHoldability)
{
ccs = x;
it.remove();
}
}
}
// Prepare CallableStatement for user
if (ccs != null)
{
ccs.setOpen();
csHit++;
if (pool.isDebug())
pool.log("CallableStatement cache hit [" + sql + "] - " + calcHitRate(csHit, csReq));
}
else
{
CallableStatement st = con.prepareCall(sql);
ccs = new CachedCallableStatement(sql, st);
ccs.setStatementListener(this);
ccs.setOpen();
if (pool.isDebug())
pool.log("CallableStatement cache miss [" + sql + "] - " + calcHitRate(csHit, csReq));
}
}
}
csUsed.add(ccs);
return ccs;
}
/**
* Callback invoked when a statement is closed.
*/
public void statementClosed(CachedStatement s) throws SQLException
{
if (s instanceof CachedPreparedStatement)
{
synchronized(ps)
{
String key = ((CachedPreparedStatement)s).getSQLString();
psUsed.remove(s);
// If caching disabled close statement
if (!cacheP)
s.release();
else // else try to recycle it
{
try
{
s.recycle();
// Place back in cache
List list = (List)ps.get(key);
if (list == null)
{
list = new ArrayList();
ps.put(key, list);
}
list.add(s);
}
catch (SQLException sqle)
{
s.release();
}
}
}
}
else if (s instanceof CachedCallableStatement)
{
synchronized(cs)
{
String key = ((CachedCallableStatement)s).getSQLString();
csUsed.remove(s);
// If caching disabled close statement
if (!cacheC)
s.release();
else // else try to recycle it
{
try
{
s.recycle();
// Place back in cache
List list = (List)cs.get(key);
if (list == null)
{
list = new ArrayList();
cs.put(key, list);
}
list.add(s);
}
catch (SQLException sqle)
{
s.release();
}
}
}
}
else if (s instanceof CachedStatement)
{
synchronized(ss)
{
ssUsed.remove(s);
// If caching disabled close statement
if (!cacheS)
s.release();
else // else try to recycle it
{
try
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -