web-dev-qa-db-ja.com

postgresでロックタイムアウトを設定する方法-Hibernate

次のコミットまで、作業中の行に Lock を設定しようとしています:

entityManager.createQuery("SELECT value from Table where id=:id")
            .setParameter("id", "123")
            .setLockMode(LockModeType.PESSIMISTIC_WRITE)
            .setHint("javax.persistence.lock.timeout", 10000)
            .getSingleResult();

2つのスレッドが同時にデータベースに書き込もうとすると、一方のスレッドが他方より先に更新操作に到達し、2番目のスレッドが10秒待ってから PessimisticLockException

ただし、代わりに、タイムアウトの設定に関係なく、スレッドは他のスレッドが終了するまでハングします。

この例を見てください:

database.createTransaction(transaction -> {
    // Execute the first request to the db, and lock the table
    requestAndLock(transaction);

    // open another transaction, and execute the second request in
    // a different transaction
    database.createTransaction(secondTransaction -> {
        requestAndLock(secondTransaction);
    });

    transaction.commit();
});

2番目のリクエストでは、トランザクションはタイムアウトが設定されるまで待機してから PessimisticLockException をスローすると予想しましたが、代わりに永久にデッドロックします。

Hibernateはこのようにして、データベースへのリクエストを生成します。

SELECT value from Table where id=123 FOR UPDATE

これで answerPostgresはタイムアウトを0に設定するSELECT FOR UPDATE NO WAITのみを許可することがわかりましたが、そのようにタイムアウトを設定することはできません。

Hibernate / JPAで使用できる他の方法はありますか?たぶん この方法 はどういうわけか推奨されますか?

10
Daniel Taub

Hibernateは クエリヒントの束 をサポートします。使用しているものは、悲観的ロックではなく、クエリのタイムアウトを設定します。クエリとロックは互いに独立しているため、以下に示すヒントを使用する必要があります。

ただし、その前に、Hibernateがタイムアウト自体を処理しないことに注意してください。それをデータベースに送信するだけであり、適用するかどうか、また適用する方法はデータベースに依存します。

悲観的ロックのタイムアウトを設定するには、代わりにjavax.persistence.lock.timeoutヒントを使用する必要があります。次に例を示します。

entityManager.createQuery("SELECT value from Table where id=:id")
        .setParameter("id", "123")
        .setLockMode(LockModeType.PESSIMISTIC_WRITE)
        .setHint("javax.persistence.lock.timeout", 10000)
        .getSingleResult();
3
Thorben Janssen

PostgresQLのロックタイムアウトのヒントはPostgreSQL 9.6では機能しません(.setHint("javax.persistence.lock.timeout", 10000

私が見つけた唯一の解決策は、postgresql.confのlock_timeoutプロパティのコメントを外すことです:

lock_timeout = 10000            # in milliseconds, 0 is disabled
1
LubošCZ

私はあなたが試すことができると思います

SET LOCAL lock_timeout = '10s';
SELECT ....;

Hibernateがこの追加設定をサポートしていないと思います。あなたはそれを価値があるかどうかわからない、それを拡張する方法を見つけることを試みることができます。 Postgesデータベース(mvcc)でロックを使用するのは最も賢明なオプションではないためです。

NO WAITおよびコードから数回遅延再試行します。

1
kan

まさにあなたが望んでいることをするlock_timeoutパラメータがあります。

postgresql.confで、またはALTER ROLEまたはALTER DATABASEを使用して、ユーザーごとまたはデータベースごとに設定できます。

0
Laurenz Albe