3

次のようなロックの問題が発生することがあります。

java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time requested

C3p0プーリングでHibernateを使用しており、オプティミスティックロック用にHibernateを構成しています。

また、Hibernateをバイパスし、独立して構成されたc3p0プーリングを介してデータベースと通信するコードもあります。これは純粋に、このコードがHibernateに移行する前に存在し、完全に機能するため、その時点で変更する必要がないことを確認したためです。

ここで、2つの独立して構成されたc3p0プールがあると、問題が発生する可能性があるのではないかと思います。これらの例外の原因を突き止める方法がない場合は、プーリングを20〜100の接続に設定し、同時に最大12のスレッドしかなく、それらを終了するとすべてのトランザクション/セッションが閉じられると思います。

編集:現在、単一のプールがありますが、それでも問題が発生し、次のエラーが発生しますが、その原因に関する詳細はありません。私が気付いたのは、常にマネージドスレッド:3と表示されていることです。

Exception with lookup
12:42:36,627  WARN ThreadPoolAsynchronousRunner:608 - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1ff96a2 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
12:42:36,628  WARN ThreadPoolAsynchronousRunner:624 - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1ff96a2 -- APPARENT DEADLOCK!!! Complete Status: 
    Managed Threads: 3
    Active Threads: 3
    Active Tasks: 
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask@fdfb9a (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask@914847 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2)
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask@205390 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1)
    Pending Tasks: 
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask@4e171b
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@ceeecb
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@19f7cec
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@1c299f9
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@10ab38a
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@1916a2f
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@1d23fbf
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@573b7c
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@1027733
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@dfd9b0
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@4cecbb
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask@4a0d0b
        com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@19e809d
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@10de0f8
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@2ce568
Pool thread stack traces:
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,JAIKOZ Thread Group]
        org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source)
        com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41)
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,JAIKOZ Thread Group]
        org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source)
        com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41)
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
    Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,JAIKOZ Thread Group]
        org.apache.derby.impl.jdbc.EmbedStatement.close(Unknown Source)
        com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:41)
        com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StatementCloseTask.run(GooGooStatementCache.java:404)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

この問題かもしれません

https://forum.hibernate.org/viewtopic.php?p=2390809

4

2 に答える 2

0

組み込み環境でHibernateで問題が発生しました。SQLiteを使用して、クライアント側のデータベース操作を実行します。組み込みデータベースには、マルチスレッド操作を処理するための限定された、または大雑把な方法があることがわかりました。トランザクションをコミットしたり、場合によっては開始したりする前に、データベースのロックをチェックする必要があります。

SQLiteを使用すると、トランザクションの進行中にスレッドに読み取りを入力させることができます。ただし、1つ以上のスレッドにトランザクションの書き込みまたはオープンを同時に行うことはできません。さらに、見つけるのが困難だった本物のsticklerは、クエリが実行されている間はトランザクションをコミットできません!そうしないと、発生したのと同様のロック例外が発生します。

私は実際にセマフォラッチロックを作成して、開いているすべての読み取り操作を追跡し、トランザクションとの安全な相互作用を可能にしました。

    /**
     * Enter read section. Increment the latch so commiting
     * threads know how many reads are left till it's appropriate
     * to write/commit.
     *
     * @throws InterruptedException the interrupted exception
     */
    public void enterReadSection() throws InterruptedException {
        if (enableReadLock && (transactionLock.availablePermits()==0)) {
            readLock.lock();
            try {
                log.debug("Waiting on database unlock.");
                readWait.await();
            } finally {
                readLock.unlock();
                log.debug("Database Unlocked.");
            }
        }

        if (enableReadLock) {
            synchronized(this) {
                latch = new CountDownLatch((int)latch.getCount()+1);
            }
        }
    }

    /**
     * Exit read section.
     */
    public void exitReadSection( ) {
        if (enableReadLock)
            latch.countDown();
    }

   /**
     * Trx lock.
     *
     * @throws InterruptedException the interrupted exception
     */
    public void trxLock() throws InterruptedException {
        if (enableTrxLock)
            transactionLock.acquire();
    }

    /**
     * Trx unlock.
     */
    public void trxUnlock() {
        if (enableTrxLock)
            transactionLock.release();
    }

    /**
     * Commit lock.
     *
     * @throws InterruptedException the interrupted exception
     */
    public void commitLock() throws InterruptedException {
        if (enableCommitLock) {
            commitLock.acquire();

            //Wait for reading threads to complete
            latch.await();
        }
    }

    /**
     * Commit unlock.
     *
     * @throws InterruptedException the interrupted exception
     */
    public void commitUnlock() throws InterruptedException {
        if(enableCommitLock) {
            commitLock.release();
            releaseRead();
        }
    }

私は知っています、そこでいくつかの深い魔法が起こっています、しかしそれは私が多くの道と誤りの後に思いついたものです。もっと簡単にできればいいのですが、通常、データベースへのクライアント/サーバーフロントエンドは同時実行性の問題の多くをオフロードするので、Oracle、mysql、postgresなどではそれほど目撃しません...

ダービーを操作するときも、ある種の並行性チェックメカニズム、セマフォ、またはラッチが必要になると思います。ダービーについてはよくわかりませんが、原始的なスレッドセーフメカニズムも組み込まれているようです。おそらく、これらの制限を回避する必要があります。幸運を!

于 2012-04-18T14:02:55.160 に答える
0

これSQLTransactionRollbackExceptionはデータベース レベルのロック エラーであるため、個別に構成された c3p0 プールだけがこの問題の原因ではありません。その場合、同じ Hibernate ベースのアプリケーションの 2 つのインスタンスを実行することはできません。

ここでの最初のステップは、例外がスローされたときにデバッガーを使用して停止することです。次に、他のデータベース接続プール スレッドをチェックして、データベースで何かを行っているかどうかを確認します。そうである場合は、データベース レベルのロックが原因でデッドロックが発生している可能性があるため、最初に確認します。問題を再現しながらプール内のスレッドの数を減らすことができれば、この手順はより簡単になります。

別のスレッドによって取得されたデータベース ロックが解放されなかったことが原因である可能性があります。その場合は、データベース ツールを使用して、例外をスローしたスレッドが取得できなかったリソースを特定し、そのロックの所有者とその理由を特定する必要があります。

幸運を。

于 2012-04-18T01:37:09.587 に答える