2009-03-19 15 views
5

Oracleデッドロック(org.hibernate.util.JDBCExceptionReporter - ORA-00060:リソースの待機中にデッドロックが検出されました)エラーが発生しました。この問題は、別のプロセスが同じ行の更新を実行している間にHibernateを使用して読み取り専用操作を実行しているプロセスであることが示唆されています。Hibernateアプリケーションが読み込み専用のデータをロードするときのデッドロック

問題の読み取り専用プロセスは、HibernateとSpringを使用して構成されています。当社は、当該サービスの取引を明示的に定義していない。これは理想的ではないかもしれませんが、私はHibernateがセーブ/アップデート操作が実行されなかったときに行に対して排他ロックを取得しようとする理由を知ることができません。

私の質問です:明示的なトランザクション管理が定義されていない場合、オブジェクトの「ロード」だけが実行されても、Hibernateは行に読み取り/書き込みロックを取得しようとしますか?保存/更新は実行されません。

データをロードしているトランザクションを定義し、次にtransactionAttributesでREADONLYを指定すると、Hibernateは既存の行ロックを無視して読み込み専用にデータをロードする可能性がありますか?ここで

は、いくつかのコードの例です:私たちはHibernateDaoTemplateを使用しているレコードをロードするための

public class HibernatePurchaseOrderDataService extends HibernateDaoSupport implements PurchaseOrderDataService { 
    public PurchaseOrderData retrieveById(Long id) { 
     return (PurchaseOrderData)getHibernateTemplate().get(PurchaseOrderData.class, id); 
    } 
} 

このメソッドを呼び出すサービスのSpring構成は次のとおりです。

<bean id="orderDataService" 
     class="com.example.orderdata.HibernatePurchaseOrderDataService"> 
    <property name="sessionFactory" ref="orderDataSessionFactory"/> 
</bean> 

<bean id="orderDataSessionFactory" 
     class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="hibernateDataSource"/> 
    <property name="hibernateProperties" ref="hibernateProperties"/> 
    <property name="mappingResources"> 
     <list> 
      <value>com/example/orderdata/PurchaseOrderData.hbm.xml</value> 
      <value>com/example/orderdata/PurchaseOrderItem.hbm.xml</value> 
     </list> 
    </property> 
</bean> 

実際にデッドロックは、PurchaseOrderをロードする呼び出しによってロードされているPurchaseOrderItemレコードの1つで発生しています。

ロードされているレコードが別のプロセスによってロックされていた場合、デッドロックが発生しますか?もしそうなら、以下のようなトランザクションラッパーを追加すると問題が解決されますか?

<bean id="txWrappedOrderDataService" 
     class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="transactionManager"/> 
    <property name="target" ref="orderDataService"/> 
    <property name="transactionAttributes"> 
    <props> 
     <!-- all methods require a transaction --> 
     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 
    </props> 
    </property> 
</bean> 

更新:データベースチームは、当社の「読み取り専用」のプロセスが実際に自動的にデータベースに書き込んでいることを示しているように見えるのサーバー上でトレースメッセージを見ています。ログに記録されている「UPDATE」コマンドは、データベースから読み取っている正確な列に対して実行されます。 Hibernateはこれらのレコードをデータベースに自動的に書き出しているように思われます(たとえそれを要求していなくても)。それはたぶんデッドロックがある理由を説明するでしょう。

セッションFLUSHなどの理由が考えられますか?ソリューションのようにもっと見ると、readOnlyを使ってトランザクションラッパーを使用することができます...

答えて

1

最終的に解決策はreadOnlyトランザクションでラップすることでした。

なぜ私たちはセッターを全く使用していなかったのか(単にデータを読む)、データベースで何も変わっていないことは明らかではありません。しかし何らかの理由でHibernateが同じデータを書き直そうとしていて、別のプロセスがそれらのレコードを読み込もうとしたときにロックを引き起こしていました。

readOnlyトランザクションを使用すると、問題が解消されました。

<bean id="txWrappedOrderDataService" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
<property name="transactionManager" ref="transactionManager"/> 
<property name="target" ref="orderDataService"/> 
<property name="transactionAttributes"> 
    <props> 
     <!-- all methods require a transaction --> 
     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 
    </props> 
</property> 

0

データベース内のトリガーをチェックしましたか?あなたはそれがHibernateであり、同じ行を更新する他のプロセスではないと確信していますか?たぶん、最後の読み取りのタイムスタンプを格納する列があり、行が読み取られるたびに更新されます(SELECTトリガーを作成できるということは私の頭の上から覚えていませんが)...

2

Involuntary実際に設定した値を操作するセッターを使用すると、休止状態で更新が行われる可能性があります。例として、nullの値を ""に置き換えるString属性の設定があります。有望な候補はコレクションでもあります。セッターが含まれているコレクションを交換しないようにしてください。エンティティのコレクションを同じ内容を含む別のコレクションに置き換えると、hibernateはそれを認識してフルコレクションを更新することができません。

+0

これは正確に起こったことではありませんが、類似しているようです。値はコード内で「設定」されていませんでした。 Hibernateは何らかの理由で同じデータを実際に書き戻そうとしていました(DB内のデータは決して異なる値に更新されませんでした)。 – jonathanq

0

イェンスは、あなたが密接に)あなたのセッターとゲッターを検査し、それらが(別の通話に 例えば新しい日付を別の値を返すかどうかを確認する必要があり、オン

追加するには権利である - これは新しい付加価値をそれぞれ返しますオブジェクトが変更されたと思っていると判断して、休止状態にします。

0

行うには面白いことの一つは、あなたのlog4j設定で

log4j.logger.org.hibernate.persister.entity.AbstractEntityPersister = TRACE

を追加することです。これを実行することによって、エンベロープがデータベース内の更新を必要とする理由がログアウトされます。プロパティがnullでDB内の更新を引き起こしたときに、エンティティにいくつかの問題が発生しました。そうすることで、私たちはそのような問題を突き止めることができました。

0

この問題は、インデックスが見つからないときに私たちのシステムで発生しています。データベースで実行されているクエリは、キー列のインデックスが失われて長時間実行されているため、テーブルがロックされています。

関連する問題