1

私のチームは、いくつかの変更を加え、古い Web アプリケーションを更新する必要があります。このアプリケーションには、1 つのメイン スレッドと、DB でデータを取得および挿入するためのワーカーとして使用される 5 ~ 15 のデーモン スレッドがあります。

これらのスレッドはすべてこの設計になっています (ここでは便宜上簡略化しています)。

public MyDaemon implements Runnable {

     // initialization and some other stuffs

     public void run() {
         ...
         while(isEnabled) {
              Engine.doTask1();
              Engine.doTask2();
              ...
              Thread.sleep(someTime);
         }
     }
}

Engine クラスは、DataAccessor クラスの他のメソッドを操作するために使用される一連の静的メソッドを提供します。これらのメソッドのいくつかは静的です。

public Engine {

    public static doTask1() {
        ThisDataAccessor.retrieve(DataType data);
        // some complicated operations
        ThisDataAccessor.insertOrUpdate(DataType data);
    }

    public static doTask2() {
        ThatDataAccessor da = new ThatDataAccessor();
        da.retrieve(DataType data);
        // etc.
    }
    ...
}

DataAccessor クラスは通常、同期されたメソッド (一部のクラスでは静的) で囲まれた単純な JDBC ステートメントを使用して DB と対話します。DataSource はサーバーで構成されます。

public ThatDataAccessor {

    public synchronized void retrieve(DataType data) {
         Connection conn = DataSource.getConnection();
         // JDBC stuff
         conn.close();
    }
    ...
}

問題は、メイン スレッドが DB に接続する必要があり、これらのデーモン スレッドが動作しているときに、プールから利用可能な接続が簡単に不足し、「接続タイムアウトの待機」例外が発生することです。さらに、それらのデーモン スレッドでさえ、同じ例外を受け取ることがあります。

この問題を取り除かなければなりません。

20 接続で構成された接続プールがあり、「20」が本番環境の標準であるため、これ以上追加することはできません。「同期」キーワードを本当に必要な場所にのみ移動する予定であっても、コードの一部のブロックを同期する必要があります。しかし、それが実際に違いを生むとは思いません。

私たちはマルチスレッド プログラミングの経験がなく、この接続プーリングの問題にこれまで直面したことがありません私たちが気づいていない欠陥はありますか?

スレッド クラスを 1 つずつプロファイリングしましたが、それらが並行して実行されていない限り、「接続タイムアウトを待っている」ことを正当化するボトルネックはないようです。アプリケーションは、Oracle 11g を使用して WebSphere 7 で実行されています。

4

1 に答える 1

1

接続をプールに戻すための finally ブロックがどこかにない可能性があります。休止状態では、これはおそらく close() を呼び出したとき、またはおそらくトランザクションで rollback() を呼び出したときに行われると思います。しかし、とにかく私は近くに電話します。

たとえば、古いアプリを拡張してマルチスレッド化するために、簡単で汚いプールを自分で作成しました。これは、処理コードの一部です (finnally ブロックを除いて、あなたにとっては意味がないはずです)。

try {
    connection = pool.getInstance();
    connection.beginTransaction();
    processFile(connection, ...);
    connection.endTransaction();
    logger_multiThreaded.info("Done processing file: " + ... );
} catch (IOException e) {
    logger_multiThreaded.severe("Failed to process file: " + ... );
    e.printStackTrace();
} finally {
    if (connection != null) {
        pool.releaseInstance(connection);
    }
}

人々がfinallyブロックを適切に使用できないことはかなり一般的です...たとえば、この休止状態のチュートリアルを見て、一番下の例にスキップしてください。try{} で tx.commit() を使用し、catch{} で tx.rollback() を使用していることがわかりますが、session.close() も、finally もありません。したがって、たとえ彼が try と catch に「session.close()」を追加したとしても、try ブロックが RuntimeException 以外のものをスローした場合、または彼の catch が try の前に追加の例外を引き起こした場合、または rollback() の前に非 HibernateException を引き起こした場合、彼の接続は閉じられません。また、session.close() がなければ、実際にはあまり良いコードではないと思います。しかし、コードが機能しているように見えても、最終的には、この種の問題から保護されているという保証が得られます。

したがって、Session を使用する彼のメソッドを書き直して、この休止状態のドキュメント ページに示されているイディオムに一致させます。(また、RuntimeException をスローすることはお勧めしませんが、それは別のトピックです)。

したがって、Hibernate を使用している場合は、上記で十分だと思います。ただし、特定のコードのヘルプが必要な場合は、より具体的にする必要がありますが、それ以外の場合は、接続を確実に閉じるために finally を使用する必要があるという単純な考えで十分です。

于 2012-06-01T08:20:07.627 に答える