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