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 の実装は上記のとおりです)。何か案が ?ありがとう、キュー。