6

Oracle デッドロック (org.hibernate.util.JDBCExceptionReporter - ORA-00060: リソースの待機中にデッドロックが検出されました) エラーが発生しています。別のプロセスが同じ行で更新を実行している間に、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 は、これらのレコードをデータベースに自動的に書き戻しているようです (私たちが要求したわけではありませんが)。それはおそらくデッドロックがある理由を説明するでしょう。

これは、Session FLUSH などの原因である可能性がありますか? 解決策のように見えるのは、読み取り専用のトランザクションラッパーを使用することです...

4

6 に答える 6

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>

于 2009-04-23T15:40:31.073 に答える
0

データベース内のトリガーを確認しましたか?それが休止状態であり、同じ行を更新する他のプロセスではないことを確認しますか?たぶん、最後に読み取られたタイムスタンプを格納する列があり、行が読み取られるたびに更新されます(ただし、SELECTトリガーを作成できることを頭の中で思い出せません)...

于 2009-03-19T22:08:39.573 に答える
0

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

于 2010-07-24T18:21:19.050 に答える
0

興味深いことの1つは、追加することです

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

あなたのlog4j構成で。そうすることで、休止状態はエンティティがデータベースで更新を必要とする理由をログに記録します。プロパティが null の場合にエンティティが "" を返すと、DB が更新されるという問題がありました。そうすることで、そのような問題を特定することができました。

于 2010-07-24T14:22:09.933 に答える
0

ジェンスは正しい

追加するには、セッターとゲッターを綿密に調べて、異なる呼び出しで異なる値を返すかどうかを確認する必要があります。

于 2009-04-14T16:19:41.007 に答える