■質問日: |
2003/04/16 |
■最終更新日: |
2007/04/19 |
■質問内容: |
DBサーバを再起動させた後、Web画面を操作すると、Oracleの場合「ORA-17002」などのエラーが発生して、DBに全くアクセスできなくなります。APサーバを再起動させれば、またアクセス可能になるのですが、APサーバを再起動せずに使用できるようにする方法はないでしょうか? |
■回答内容: |
DB接続に DataSourceConnection を使用している場合は、お使いのJDBCデータソースの 設定により、再接続を行ってください。 Tomcat 5.5.xを利用した場合の、設定例: auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@wwb.ws.sios.com:1521:WWBDB2" username="wdc_test" password="wdc_test" maxActive="3" maxIdle="0" maxWait="1000" removeAbandoned="true" validationQuery="SELECT 'A' FROM DUAL" /> DB接続に LocalConnection を使用しているのであれば下記のようにすることで可能となります。 (APサーバのコネクションプールを使用していない。) ただし、WDC 1.20_047p3、あるいはWDC 1.30-004以降が必要です。 (WDC 1.20-048などは対象外ですので注意してください。) 最初にアクセスした人はエラーになってしまいますが、 次からは正常にDBにアクセスすることができます。 添付資料のソースにように下記の2つのクラスを作成します。 MyLocalConnection ・・・ LocalConnectionクラスを継承 MyQueryAgentManager ・・・ QueryAgentManagerクラスを継承 (※これらはサンプルです。環境に合わせてカスタマイズしてください。) MyQueryAgentManagerのFATAL_ERROR_CODEには、エラーが起きた後に コネクションプールをリセットするORACLEのエラーコードを定義 しておきます。(クエリー実行時に発生したエラーコードが、FATAL_ERROR_CODE に定義されていた場合、コネクションプールをリセットします。) これらの拡張されたコネクションプールを利用するために web.xml に 下記を定義します。 client_connection_impl_class_name jp.co.tenartni.samples.maido.xqa.MyLocalConnection パラメタの意味:クライアントコネクションの実装クラス名です。 パラメタ値のデフォルト:jp.co.tenartni.xqa.LocalConnection ※注 このサンプルはRDBMS本体およびDBサーバ間の接続には異常がないけれども、APサーバ=DBサーバ間の接続が切断されてしまった場合に再接続を行うためのです。 (例えば、夜間にRDBMSを正常に停止させバックアップを取った後、RDBMSを正常に再起動させた場合など) RDBMSに障害が発生した場合などは動作いたしません。 |
■添付資料: |
-- MyLocalConnectionクラス package jp.co.tenartni.samples.maido.xqa; import jp.co.tenartni.data.*; import jp.co.tenartni.xqa.*; import jp.co.tenartni.log.*; /** * MyLocalConnectionクラス. * * LocalConnectionクラスを拡張している。 * QueryAgentManagerとして、重大なエラーが発生した後にコネクションプールを * リセットする機能が追加されているMyQueryAgentManagerクラスを利用する。 * */ public class MyLocalConnection extends LocalConnection { private transient static java.util.Hashtable myInternalManagerTable = new java.util.Hashtable(); private transient MyQueryAgentManager myInternalManager = null; private transient static Logger logger = LogManager.getLogger(MyLocalConnection.class.getName()); public MyLocalConnection() { super(); } public void open() throws QueryAgentException { try { if (myInternalManagerTable==null) { myInternalManagerTable = new java.util.Hashtable(); } if (getInternalManager()==null) { String registKey = null; if (isCreateInstanceByParam()) registKey = this.getDbUrl() + "/" + this.getDbUserName() + "/" + this.getDbClassName() + "/" + isUseSchema() + "/" + isUseUpperCase() + "/" + this.getHelperClassName(); else registKey = this.getPropertyFileName() + "/" + this.getQueryAgentName(); if (registKey==null) throw new Exception(Msg.CONNECTION_INIT_PARAM_LACK); setInternalManager((MyQueryAgentManager)(myInternalManagerTable.get(registKey))); if (getInternalManager()==null) { if (isCreateInstanceByParam()) setInternalManager(new MyQueryAgentManager( registKey, this.getDbClassName(), this.getDbUrl(), this.getDbUserName(), this.getDbPassword(), this.getMinAgent(), this.getMaxAgent(), this.isUseUpperCase(), this.isUseSchema(), this.getHelperClassName(), false, this.getMaxWaitSec() )); else setInternalManager(new MyQueryAgentManager(this.getPropertyFileName(), this.getQueryAgentName(), false)); myInternalManagerTable.put(registKey, getInternalManager()); } } } catch (Exception ex) { String msg = Msg.QUERY_AGENT_GENERATE_ERROR + ex.getMessage(); logger.error(msg); logger.error(ex); throw new QueryAgentException(ex, msg); } } protected void setInternalManager(MyQueryAgentManager myQueryAgentManager) { this.myInternalManager = myQueryAgentManager; } protected void setInternalManager(QueryAgentManager myQueryAgentManager) { this.myInternalManager = (MyQueryAgentManager)myQueryAgentManager; } protected QueryAgentManager getInternalManager() { return this.myInternalManager; } } -- MyQueryAgentManagerクラス package jp.co.tenartni.samples.maido.xqa; import jp.co.tenartni.*; import jp.co.tenartni.sql.*; import jp.co.tenartni.xqa.*; import jp.co.tenartni.log.*; /** * MyQueryAgentManagerクラス. * * QueryAgentManagerクラスを拡張している。 * 重大なエラーが発生した後にコネクションプールをリセットする機能を追加している。 * */ public class MyQueryAgentManager extends QueryAgentManager { private final static int[] FATAL_ERROR_CODE = new int[]{ 28 // セッションは強制終了されました。 ,2396 // 最大アイドル時間を越えた。 ,3113 // 通信チャネルでend-of-fileが検出されました。 ,3114 // Oracleに接続されていません。 ,17002 // I/O例外です。 }; private transient static Logger logger = LogManager.getLogger(MyQueryAgentManager.class.getName()); /** * Constructor for MyQueryAgentManager. */ public MyQueryAgentManager() { super(); } /** * Constructor for MyQueryAgentManager. */ public MyQueryAgentManager( String arg0, String arg1, String arg2, String arg3, String arg4, int arg5, int arg6, boolean arg7, boolean arg8, String arg9, boolean arg10, int arg11) throws QueryAgentException { super(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } /** * Constructor for MyQueryAgentManager. * @throws QueryAgentException */ public MyQueryAgentManager(String arg0, String arg1, boolean arg2) throws QueryAgentException { super(arg0, arg1, arg2); } protected void doAfterExecuteError(WWBException ex, QueryAgent agent, SQLHandler sqlHandler) throws QueryAgentException { //System.out.println("MyQueryAgentManagerでエラー発生"); // 重大なエラーが発生していれば、コネクションプールをリセットする。 boolean fatalErrorFound = false; Exception x = ex; while (x != null) { if (x instanceof WWBException) { x = ((WWBException)x).getException(); } else { break; } } if (x instanceof java.sql.SQLException) { while (x != null) { int errorCode = ((java.sql.SQLException)x).getErrorCode(); if (isFatalError(errorCode)) { logger.fatal("致命的なエラーが発生したので、コネクションプールをリセットします。エラーコード:"+errorCode); fatalErrorFound = true; break; } else { // 次のエラーを取得する。 x = ((java.sql.SQLException)x).getNextException(); } } } if (fatalErrorFound) { // コネクションプールのリセット // inactiveなQueryAgent全てと今回SQLを発行したQueryAgentを削除する。 synchronized (this.inactiveAgent) { // inactiveなQueryAgentの削除 Object[] agents = new Object[this.inactiveAgent.size()]; this.inactiveAgent.copyInto(agents); for (int i=0; i this.destroyAgent((QueryAgent)(agents[i])); } // 今回SQLを発行したQueryAgentの削除 this.destroyAgent(agent); } throw new QueryAgentException(ex, "致命的なエラーが発生したので、コネクションプールをリセットしました。 再度、ログインしてください。"); } throw new QueryAgentException(ex); } private boolean isFatalError(int errorCode) { boolean found = false; int[] fatalErrorCode = getFatalErrorCode(); for (int i=0; i if (fatalErrorCode[i] == errorCode) { found = true; break; } } return found; } private int[] getFatalErrorCode() { return FATAL_ERROR_CODE; } } |