10

Spring のリスナーで Hibernate を使用していますDefaultMessageLisenerContainer

リスナーを複数のスレッドで実行するとStaleStateException、読み取り専用操作で次のような問題が発生することがよくあります。

Query q = session.createQuery("SELECT k FROM Keyword k WHERE k.name = :name").setParameter("name", keywordName);
List<Keyword> kws = q.list()

q.list() で例外がスローされます。

楽観的ロックが失敗しました。ネストされた例外は org.hibernate.StaleObjectStateException: 行が別のトランザクションによって更新または削除されました (または、保存されていない値のマッピングが正しくありませんでした)

Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.aurora.common.model.Keyword#7550]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1934)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2578)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2478)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:114)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:267)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:259)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:179)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1251)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)

読み取り操作は、バージョンの競合をチェックしてStaleObjectStateException.

name属性が Keyword オブジェクトの主キーではありません。

更新: 私のデータ アクセス コード:HibernateTransactionManagerスレッド バインドの Hibernate セッションをサポートする Spring を使用しています。Hibernate セッションは、SessionFactory.getCurrentSession() メソッドを通じて取得されます。

HibernateTransactionManager を MessageListenerContainer に割り当てることにより、各トランザクションはリスナーの呼び出しをラップします。

<jms:listener-container connection-factory="connectionFactory" concurrency="3-3" prefetch="6" transaction-manager="transactionManager">
        <jms:listener destination="${requests}" response-destination="${replies}" ref="chunkHandler" method="handleChunk" />
    </jms:listener-container>

UPDATE : 提案された回答のように、staleObjectStateException を引き起こす他の操作がある可能性があります。それ以前の他のすべての操作のために、Session.isDirty() をログアウトしようとしました。それらはすべて読み取り操作です。興味深いことに、名前によるキーワード選択操作の後、セッションは実際にはダーティとしてマークされます。実際のコードは次のようなものです。

for (String n : keywordNames) {
    Keyword k = keywordDao.getKeywordByName(n);
}

最初の繰り返しの後、セッションはダーティです。(KeywordDao.getKeywordByName の実装は上記のとおりです)。何か案が ?ありがとう、キュー。

4

3 に答える 3

14

与えられた他の答えは正しくないと思います。存在しない行にアクセスしても StaleObjectStateException は発生せず、単にエンティティをクエリしても、そのエンティティの楽観的ロックはトリガーされません。

スタック トレースをさらに調べると、原因のヒントが得られます。

at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)query.list() を呼び出すとき

at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175)Hibernate は、セッションの自動フラッシュが必要かどうかを判断します。何らかの理由で、Hibernate は自動フラッシュが必要であると考えています。(おそらく、以前に同じセッションでいくつかの Keyword エンティティ、または他のエンティティを更新したことが原因です...それは正直に言えません)

at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)その後、Hibernate はセッション内のすべての変更を DB にフラッシュします。そして、ここで StaleObjectStateException の問題が発生します。これは、Optimistic Concurrency チェックの失敗を意味します。オプティミスティック コンカレンシー チェックの失敗は、キーワード エンティティに関連している可能性があります。関連していない可能性もあります (セッション内の更新されたすべてのエンティティを単に DB にフラッシュしているため)。ただし、あなたの場合、実際にはKeywordエンティティ(Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.ncs.singtel.aurora.common.model.Keyword#7550])に関連しています

オプティミスティック コンカレンシー エラーの原因を確認してください。通常、オプティミスティック同時実行例外を呼び出し元に再スローし、関数を再度呼び出すかどうかを呼び出し元に決定させるだけです。ただし、それはすべてあなたのデザインに依存します。

于 2013-01-21T06:27:39.337 に答える
1

stalestateException存在しない行にアクセスしようとすると発生します。keyword.getName()それが何を返すかを確認するためにあなたをチェックしてください。

于 2013-01-21T05:10:04.003 に答える
0

他のいくつかのトランザクションは、読み取りと同時に Keyword エンティティを更新している可能性があり、読み取り操作により古いオブジェクトが発生する可能性があります。

これが楽観的ロックです。悲観的ロックを検討できますが、パフォーマンスに深刻な影響を与えます。

キャッチStaleObjectStateExceptionしてもう一度読み直すことをお勧めします。

于 2013-01-21T05:19:33.847 に答える