3

特定の状態のデータベースからすべてのオブジェクトを読み取る Singleton-EJB があります。次に、これらのオブジェクトで何かを行い、状態を別のものに設定します。

@Singleton
public class MyEJB {

    @PersistenceContext(unitName = "MyPu")
    private EntityManager em;

    @Lock(LockType.WRITE)
    public void doSomeStuffAndClose() {
        List<MyObj> objects = getAllOpenObjects();
        for (MyObj obj : objects) {
            // do some stuff here...
            obj.setClosed(true);
        }
    }

    private List<MyObj> getAllOpenObjects() {
        TypedQuery<MyObj> q = em.createQuery("select o from MyObj o "
            + "where o.closed = false", MyObj.class);
        return q.getResultList();
    }
}

ここで、メソッドが同時に呼び出されないようにしたい場合は、注釈を追加し@Lock(LockType.WRITE)ます。ただし、データベースに状態を設定するトランザクションは、ロックが解放された後にコミットされ、次の呼び出し元が同じオブジェクトを再度取得する可能性があります。

どうすればこれを防ぐことができますか?

4

5 に答える 5

2

Wildfly を使用している場合: これはバグです。https://issues.jboss.org/browse/WFLY-4844は、Wildfly 10 で修正される問題について説明しています。この問題は、タイマーの問題として説明されていますが、これはあなたの問題と同じかもしれません。

私の回避策は、作業を行うコードを、外部 (タイマー) Bean によって呼び出される別の Bean に分離することです。外側の Bean メソッドには、トランザクションを開始しないように注釈が付けられている@TransactionAttribute(TransactionAttributeType.NEVER)ため ( )、トランザクションは 2 番目の新しい Bean で開始され、安全に終了します。

于 2016-02-12T05:42:05.977 に答える
1

SELECT FOR UPDATE を使用して、行のアクセスをシリアル化できます。

JPA 2 では LockModeType を使用します: http://docs.oracle.com/javaee/6/api/javax/persistence/LockModeType.html

q.setLockMode(LockModeType.PESSIMISTIC_WRITE)
于 2013-10-17T13:53:32.637 に答える
0

JPAでこれを行う方法はありません(つまり、移植可能な方法で)。オプションは次のとおりです。

  1. 一部の JPA 実装では、クエリごとに分離レベルを設定できますが (例: OpenJPA )、そうでないものもあります (Hibernate)。ただし、OpenJPA であっても、このヒントは特定のデータベース ドライバーに実装する必要があります。そうしないと効果がありません)。
  2. ネイティブ クエリの実行 - 詳細については、データベースのドキュメントを参照してください。

余談ですが、JPA (および一般的な Java EE) は、大量のデータベース操作を念頭に置いて設計されているわけではありません。むしろ、ほとんどの場合重複しないデータ項目に対する複数の同時クエリ用です。

于 2013-10-01T15:24:20.613 に答える