JBOSS接続プール4-接続取得および返却と破棄
14542 ワード
このセクションでは、getconnection(接続の取得)とreturnConnection(接続の解放)の2つの最も重要な方法について説明します.最後に、JBOSSで異常接続がどのように破棄されたかを補足します.
アプリケーションがビジネス処理を行う必要がある場合、まずgetConnectionの操作を実行し、接続プールから接続を取得し、ビジネス処理が完了した後、接続プールに接続を戻し、returnConnectionの操作を実行する必要があります.次にgetConnectionのソースコードを見てみましょう.
実行プロセスフローチャートは次のとおりです.
getConnetionについてのいくつかの説明1.blockingTimeoutはjbossのパラメータ:5000 であり、信号量を取得するタイムアウト時間であり、より正確には接続プールから接続を取得するタイムアウト時間である.5000 msを超えると信号量(接続)が取得できない場合、jbossは「can not get connection,No ManagedConnections available within configured blocking timeout[xx]ms」という異常を投げ出す.もちろん、現在使用されている接続数がMAX値に達していない限り、この信号量は必ず取得できる.信号量は全部でMAXの値があるので、接続プールの現在の接続が足りない場合は、信号量を取得した後、新しい接続を作成すればよい.500 ms程度に設定できるようにすることが推奨され、設計が大きすぎる必要がなく、アプリケーションに複数のデータソースが存在する場合、DB異常スレッドプールによるブロックを防止することができる.ネットワーク環境が悪ければ、もっと高く設定できます.
2.接続プールの内部には、接続傍受キューがあり、毎回キューの末尾から接続を取得します.IdleRemoveスレッドは、このキューヘッダからクリーンアップされます.
3.接続プールの取得、破棄、作成の3つの操作は、スレッドの安全な操作です.
4.トラフィックは、接続を使用する間、この信号量を常に占有し、returnConnectionまたは異常が発生した場合に信号量を解放します.信号量を取得できることは、接続が必ず取得できることを意味する.第2節では,JBOSSは起動時に信号量配列を初期化し,長さは接続プールのmaxパラメータである.
ビジネスシステムが接続を使用した後、接続を接続プールに戻す必要があります.主に下図を参照してください.ソースコードは以下の通りです.
実行プロセスフローチャートは次のとおりです.
ReturnConnetionまとめ:1.接続を解放するのもスレッドの安全な操作です.2.return接続時に既にdestoryの状態になっている可能性があります(前の第3節で述べたSHUTDOWN操作では、接続にDESTORYのマークが付けられます)、この場合、そのままremoveを行えばよいです.3.解放された接続が接続傍受キュー(接続プール)に属さない場合、接続傍受キュー(接続プール)に追加されます.4.接続を解放するには、信号量を解放する必要がある.5.リリース中に例外が発生した場合、接続は接続プールから削除され、強制破棄されます.
JBOSS異常接続の処理:デフォルトでは、JBOSSは無効な接続を破棄しません.異常リストの接続を破棄する必要がある場合は、接続プールのdsが必要です.xmlに次の構成を追加します.
これはORACLEの異常リストです.このクラスに定義されているORACLEの異常リストを表示できます.接続がこのリストのエラーを投げ出すと、破棄されます.破棄できない場合は、異常接続は接続プールに存在します.ORACLE異常リストは以下の通りです.
同様に、MYSQLの異常リストも見つけることができます.org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter:
また、様々なデータベースの例外リストは、自分で構成することができ、このパッケージの下で定義されています:org.jboss.resource.adapter.jdbc.vendor.
この記事は以下のとおりです.http://www.dbafree.net/?p=378
アプリケーションがビジネス処理を行う必要がある場合、まずgetConnectionの操作を実行し、接続プールから接続を取得し、ビジネス処理が完了した後、接続プールに接続を戻し、returnConnectionの操作を実行する必要があります.次にgetConnectionのソースコードを見てみましょう.
//getConnection ConnectionListener
public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri)
throws ResourceException
{
subject = (subject == null) ? defaultSubject : subject;
//
cri = (cri == null) ? defaultCri : cri;
// startWait, ,
long startWait = System.currentTimeMillis();
try
{
/* xx (permit), permit 。
* permit , 。
, , max ,
, max , 。
, , max ,
, , 。
*/
if (permits.attempt(poolParams.blockingTimeout))
{
// = -
long poolBlockTime = System.currentTimeMillis() - startWait ;
// 。
connectionCounter.updateBlockTime(poolBlockTime);
// , ?
ConnectionListener cl = null;
do
{
// ,
synchronized (cls)
{
// shutdown, shutdown,
// "The pool has been shutdown",
if (shutdown.get())
{
permits.release();
throw new ResourceException("The pool has been shutdown");
}
// arraylist 0, arraylist
if (cls.size() > 0)
{
cl = (ConnectionListener) cls.remove(cls.size() - 1);
// arraylist checkdout hash .
checkedOut.add(cl);
//
int size = (int) (maxSize - permits.permits());
//
if (size > maxUsedConnections)
maxUsedConnections = size;
}
}
//
if (cl != null)
{
// pool ManagedConnection, ?
try
{
Object matchedMC = mcf.matchManagedConnections
(Collections.singleton(cl.getManagedConnection())
,subject, cri);
if (matchedMC != null)
{
if (trace)
log.trace("supplying ManagedConnection from pool: " + cl);
// connection listener
cl.grantPermit(true);
// ,
return cl;
}
/*
* , 。
* , ,
, , , 。
*/
log.warn("Destroying connection that could not be
successfully matched: " + cl);
synchronized (cls)
{
// checkout hashset 。
checkedOut.remove(cl);
}
//
doDestroy(cl);
cl = null;
}
// ,
catch (Throwable t)
{
log.warn("Throwable while trying to match ManagedConnection,
destroying connection: " + cl, t);
synchronized (cls)
{
checkedOut.remove(cl);
}
doDestroy(cl);
cl = null;
}
// , ,
// jboss useFastFail , false。
// useFastFail true, get connection, 。
if(poolParams.useFastFail)
{
log.trace("Fast failing for connection attempt.
No more attempts will be made to acquire connection from pool
and a new connection will be created immeadiately");
break;
}
}
}
// >0,
while (cls.size() > 0);//end of do loop
//OK, ,
try
{
// 。 max
// , 。
cl = createConnectionEventListener(subject, cri);
synchronized (cls)
{ // checkout 。
checkedOut.add(cl);
int size = (int) (maxSize - permits.permits());
//
if (size > maxUsedConnections)
maxUsedConnections = size;
}
// , , started true。
// ( ), 。
if (started == false)
{
started = true;
if (poolParams.minSize > 0)
PoolFiller.fillPool(this);
}
if (trace)
log.trace("supplying new ManagedConnection: " + cl);
// connection listener
cl.grantPermit(true);
return cl;
}
catch (Throwable t)
{
log.warn("Throwable while attempting to get a new connection: " + cl, t);
//return permit and rethrow
synchronized (cls)
{
checkedOut.remove(cl);
}
permits.release();
JBossResourceException.rethrowAsResourceException(
"Unexpected throwable while trying to create a connection: " + cl, t);
throw new UnreachableStatementException();
}
}
// else , , , 。
else
{
// we timed out
throw new ResourceException("No ManagedConnections available
within configured blocking timeout ( "
+ poolParams.blockingTimeout + " [ms] )");
}
}
catch (InterruptedException ie)
{
long end = System.currentTimeMillis() - startWait;
connectionCounter.updateBlockTime(end);
throw new ResourceException("Interrupted while requesting permit!
Waited " + end + " ms");
}
}
実行プロセスフローチャートは次のとおりです.
getConnetionについてのいくつかの説明1.blockingTimeoutはjbossのパラメータ:
2.接続プールの内部には、接続傍受キューがあり、毎回キューの末尾から接続を取得します.IdleRemoveスレッドは、このキューヘッダからクリーンアップされます.
3.接続プールの取得、破棄、作成の3つの操作は、スレッドの安全な操作です.
4.トラフィックは、接続を使用する間、この信号量を常に占有し、returnConnectionまたは異常が発生した場合に信号量を解放します.信号量を取得できることは、接続が必ず取得できることを意味する.第2節では,JBOSSは起動時に信号量配列を初期化し,長さは接続プールのmaxパラメータである.
ビジネスシステムが接続を使用した後、接続を接続プールに戻す必要があります.主に下図を参照してください.ソースコードは以下の通りです.
public void returnConnection(ConnectionListener cl, boolean kill) {
synchronized (cls) {
/*
* DESTROYED?
* background-validation shuwdown
* DESTORYED 。
*
*/
if (cl.getState() == ConnectionListener.DESTROYED) {
if (trace)
log
.trace("ManagedConnection is being returned after it was destroyed"
+ cl);
// ,
if (cl.hasPermit()) {
// release semaphore
cl.grantPermit(false);
permits.release();
}
return;
}
}
if (trace)
log.trace("putting ManagedConnection back into pool kill=" + kill
+ " cl=" + cl);
try {
// 。
cl.getManagedConnection().cleanup();
} catch (ResourceException re) {
log.warn("ResourceException cleaning up ManagedConnection: " + cl,
re);
// , , 。
kill = true;
}
synchronized (cls) {
// DESTROY DESTROYED, kill true
if (cl.getState() == ConnectionListener.DESTROY
|| cl.getState() == ConnectionListener.DESTROYED)
kill = true;
//checkedOut 。
checkedOut.remove(cl);
// kill==false, >= max , , kill=true
if (kill == false && cls.size() >= poolParams.maxSize) {
log
.warn("Destroying returned connection, maximum pool size exceeded "
+ cl);
kill = true;
}
//kill
if (kill) {
// Adrian Brock: A resource adapter can asynchronously notify us
// that
// a connection error occurred.
// This could happen while the connection is not checked out.
// e.g. JMS can do this via an ExceptionListener on the
// connection.
// I have twice had to reinstate this line of code, PLEASE DO
// NOT REMOVE IT!
cls.remove(cl);
}
// kill==false
else {
cl.used();
// , 。
if (cls.contains(cl) == false)
cls.add(cl);
else
log.warn("Attempt to return connection twice (ignored): "
+ cl, new Throwable("STACKTRACE"));
}
if (cl.hasPermit()) {
//
cl.grantPermit(false);
permits.release();
}
}
if (kill) {
if (trace)
log.trace("Destroying returned connection " + cl);
// 。
doDestroy(cl);
}
}
実行プロセスフローチャートは次のとおりです.
ReturnConnetionまとめ:1.接続を解放するのもスレッドの安全な操作です.2.return接続時に既にdestoryの状態になっている可能性があります(前の第3節で述べたSHUTDOWN操作では、接続にDESTORYのマークが付けられます)、この場合、そのままremoveを行えばよいです.3.解放された接続が接続傍受キュー(接続プール)に属さない場合、接続傍受キュー(接続プール)に追加されます.4.接続を解放するには、信号量を解放する必要がある.5.リリース中に例外が発生した場合、接続は接続プールから削除され、強制破棄されます.
JBOSS異常接続の処理:デフォルトでは、JBOSSは無効な接続を破棄しません.異常リストの接続を破棄する必要がある場合は、接続プールのdsが必要です.xmlに次の構成を追加します.
< exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
< /exception-sorter-class-name>
これはORACLEの異常リストです.このクラスに定義されているORACLEの異常リストを表示できます.接続がこのリストのエラーを投げ出すと、破棄されます.破棄できない場合は、異常接続は接続プールに存在します.ORACLE異常リストは以下の通りです.
public boolean isExceptionFatal(final SQLException e)
{
// I can't remember if the errors are negative or positive.
final int error_code = Math.abs( e.getErrorCode() );
if( ( error_code == 28 ) //session has been killed
|| ( error_code == 600 ) //Internal oracle error
|| ( error_code == 1012 ) //not logged on
|| ( error_code == 1014 ) //Oracle shutdown in progress
|| ( error_code == 1033 ) //Oracle initialization or shutdown in progress
|| ( error_code == 1034 ) //Oracle not available
|| ( error_code == 1035 ) //ORACLE only available to users with RESTRICTED SESSION privilege
|| ( error_code == 1089 ) //immediate shutdown in progress - no operations are permitted
|| ( error_code == 1090 ) //shutdown in progress - connection is not permitted
|| ( error_code == 1092 ) //ORACLE instance terminated. Disconnection forced
|| ( error_code == 1094 ) //ALTER DATABASE CLOSE in progress. Connections not permitted
|| ( error_code == 2396 ) //exceeded maximum idle time, please connect again
|| ( error_code == 3106 ) //fatal two-task communication protocol error
|| ( error_code == 3111 ) //break received on communication channel
|| ( error_code == 3113 ) //end-of-file on communication channel
|| ( error_code == 3114 ) //not connected to ORACLE
|| ( error_code >= 12100 && error_code = 21000 ) &&
( (error_text.indexOf("SOCKET") > -1) //for control socket error
|| (error_text.indexOf("CONNECTION HAS ALREADY BEEN CLOSED") > -1)
|| (error_text.indexOf("BROKEN PIPE") > -1) ) )
{
return true;
}
return false;
}
同様に、MYSQLの異常リストも見つけることができます.org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter:
public boolean isExceptionFatal(SQLException e)
{
if (e.getSQLState() != null)
{ // per Mark Matthews at MySQL
if (e.getSQLState().startsWith("08"))
{
return true;
}
}
switch (e.getErrorCode())
{
// Communications Errors
case 1040: // ER_CON_COUNT_ERROR
case 1042: // ER_BAD_HOST_ERROR
case 1043: // ER_HANDSHAKE_ERROR
case 1047: // ER_UNKNOWN_COM_ERROR
case 1081: // ER_IPSOCK_ERROR
case 1129: // ER_HOST_IS_BLOCKED
case 1130: // ER_HOST_NOT_PRIVILEGED
// Authentication Errors
case 1045: // ER_ACCESS_DENIED_ERROR
// Resource errors
case 1004: // ER_CANT_CREATE_FILE
case 1005: // ER_CANT_CREATE_TABLE
case 1015: // ER_CANT_LOCK
case 1021: // ER_DISK_FULL
case 1041: // ER_OUT_OF_RESOURCES
// Out-of-memory errors
case 1037: // ER_OUTOFMEMORY
case 1038: // ER_OUT_OF_SORTMEMORY
return true;
}
return false;
}
また、様々なデータベースの例外リストは、自分で構成することができ、このパッケージの下で定義されています:org.jboss.resource.adapter.jdbc.vendor.
この記事は以下のとおりです.http://www.dbafree.net/?p=378