[英]Connection pooling jdbc
您可以在這里看到我們正在使用我們自己的內部連接池,而不是使用commons.dcbp連接池,因此在服務器xml中更改連接設置不會執行任何操作。 處理測試/刪除陳舊連接的最佳方法是什么? 在getConnection()方法中進行驗證查詢會更好還是在一定時間后僅從連接池中刪除連接會更好(以及如何執行此操作)?
//working connection
[18 Mar 23:19:01] (ajp-nio-8701-exec-5) INFO : pconn: com.peregrine.esf.jdbc.PoolableConnection@782d14dd pconn.isStreamOpen(): true
//after about an hour, tries to grab same connection from pool but it is already closed by db
[19 Mar 00:26:19] (ajp-nio-8701-exec-1) INFO : pconn: com.peregrine.esf.jdbc.PoolableConnection@782d14dd pconn.isStreamOpen(): true
[19 Mar 00:26:19] (ajp-nio-8701-exec-1) ERROR: java.sql.SQLException: Io exception: Connection reset
java.sql.SQLException: Io exception: Connection reset
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:74)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:131)
at
public final class DefaultConnectionPool implements ConnectionPool
{
private final static Logger log = Logger.getLogger(DefaultConnectionPool.class);
private Connector mConnector;
/** Maximum number of connections to allow. */
private final int mMaxConn;
/** Number of open connections. */
protected int mOpen;
/** List of unused, open connections. */
private final LinkedList mConns = new LinkedList();
/** Count of threads wait for a connection. */
private int mWaiting;
private int mWaitInfo;
private int mWaitWarn;
private final int mThreshold;
public DefaultConnectionPool(Connector connector, int poolSize)
{
mConnector = connector;
mMaxConn = poolSize;
mThreshold = Math.max( 1, mMaxConn );
}
public PoolSnapshot getSnapshot()
{
PoolSnapshot p = new PoolSnapshot();
p.mMaxConn = mMaxConn;
p.mOpen = mOpen;
p.mWaiting = mWaiting;
p.mIdle = mConns.size();
return p;
}
private StringBuffer buildWaitingMessage()
{
StringBuffer buffer = new StringBuffer(100);
buffer.append( Integer.toString( mWaiting ) );
buffer.append( " thread(s) waiting for one of " );
buffer.append( Integer.toString( mMaxConn ) );
buffer.append( " pooled connections" );
return buffer;
}
/**
* Return a connection that we're finished with back to the pool.
* @param conn
*/
public synchronized void returnToPool( final Connection conn )
{
if (conn != null)
mConns.add( conn );
notifyAll();
}
/**
* Create a new PoolableConnection decorating a real connection.
* @param conn
* @throws java.sql.SQLException
* @return
*/
synchronized protected PoolableConnection create( final Connection conn ) throws SQLException
{
PoolableConnection pconn = new PoolableConnection( conn );
mOpen++;
return pconn;
}
/**
* Destroy a poolable connection.
* @param conn
*/
synchronized public void destroy( final Connection conn )
{
if (conn instanceof PoolableConnection)
{
PoolableConnection pConn = (PoolableConnection) conn;
if (pConn.getPool() == this)
{
mOpen--;
pConn.destroy();
notifyAll();
}
}
}
synchronized public Connection recycle(final Connection conn) throws SQLException
{
if (conn instanceof PoolableConnection)
{
PoolableConnection pConn = (PoolableConnection) conn;
if (pConn.getPool() == this)
{
pConn.destroy();
pConn = null;
Connection newConn = mConnector.getConnection();
if (newConn != null)
{
PoolableConnection p = new PoolableConnection( newConn );
p.open(this);
return p;
}
}
}
return null;
}
/**
* Get a pooled connection, or wait for one to become available.
* @throws java.sql.SQLException
* @return
*/
synchronized public Connection getConnection() throws SQLException
{
log.info("...getdefaultconnection");
PoolableConnection pconn;
log.info("mConns.size(): "+mConns.size()+" mOpen: "+mOpen+" mMaxConn: "+mMaxConn);
// do we need to wait?
if (mConns.isEmpty() && (mOpen == mMaxConn))
{
mWaiting++;
try
{
// do we want to warn?
if (mWaiting >= mMaxConn)
{
// did we hit logging threshhold?
if ((mWaitWarn % mThreshold) == 0)
{
log.info( buildWaitingMessage() );
}
mWaitWarn++;
mWaitInfo++;
}
// else, we want to inform
else
{
// did we hit logging threshhold?
if ((mWaitInfo % mThreshold) == 0)
{
log.info( buildWaitingMessage() );
}
mWaitInfo++;
}
// wait while max connections are in use
while (mConns.isEmpty() && (mOpen == mMaxConn))
{
try { wait(250); } catch( InterruptedException ignored ) {}
}
}
finally
{
// done waiting. Reset counters if necessary
mWaiting--;
if (mWaiting == 0)
{
mWaitInfo = 0;
mWaitWarn = 0;
}
}
}
// get a connection
if (mConns.isEmpty())
{
Connection conn = mConnector.getConnection();
pconn = create( conn );
}
else
{
pconn = (PoolableConnection) mConns.removeFirst();
log.info("pconn: "+pconn+" pconn.isStreamOpen(): "+pconn.isStreamOpen());
}
pconn.open( this );
return pconn;
}
public synchronized void shutDown()
{
log.debug("DefaultConnectionPool shutting down...");
Iterator itor = mConns.iterator();
while (itor.hasNext())
{
PoolableConnection conn = (PoolableConnection)itor.next();
conn.destroy();
log.debug("Connection [" + conn.toString() + "] shutdown.");
conn = null;
}
}
}
連接池框架通常會根據您所討論的內容提供以下設置/功能:
Select 1
用於SQLServer)。 大多數框架都具有此類設置(以及許多其他設置)。 您應該研究幾個常見的比較和了解。
至於它們是如何實現的。 通常,框架將在后台運行1個或多個線程以執行檢查和清理。 實際上,為此分配的線程數通常也是可配置的。
您應該真正考慮遷移到經過良好測試的正式框架。 與廣泛使用的框架相比,在這種情況下嘗試重新發明輪子可能永遠不會獲得穩定的結果。
如果您必須繼續使用自己的自制框架。 我的猜測是您無法更改每個訪問您的池類的人的API。 您可以通過在應用程序內配置這些框架之一來減輕過渡的痛苦,並通過更改DefaultConnectionPool
類的內部以委托給框架提供的框架來“橋接” API。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.