jon*_*anq 5 oracle spring deadlock hibernate
我们遇到Oracle死锁(org.hibernate.util.JDBCExceptionReporter - ORA-00060:在等待资源时检测到死锁)错误.有人建议问题在于使用Hibernate执行只读操作的进程,而另一个进程在同一行上执行更新.
有问题的只读进程是使用Hibernate和Spring配置的.我们没有明确定义服务的事务.虽然这可能不太理想 - 我不明白为什么Hibernate会在没有执行保存/更新操作时尝试在行上获得独占锁定 - 只有get/load.
所以我的问题是:当没有定义显式事务管理时,Hibernate是否尝试在一行上获得读/写锁,即使只执行了对象的"加载".不执行保存/更新.
是否有可能围绕正在加载数据的服务定义一个事务,然后在transactionAttributes上特别说READONLY会导致Hibernate忽略已经存在的行锁并只是加载数据以用于只读目的?
以下是一些代码示例:
为了加载记录,我们使用的是HibernateDaoTemplate
public class HibernatePurchaseOrderDataService extends HibernateDaoSupport implements PurchaseOrderDataService {
public PurchaseOrderData retrieveById(Long id) {
return (PurchaseOrderData)getHibernateTemplate().get(PurchaseOrderData.class, id);
}
}
Run Code Online (Sandbox Code Playgroud)
调用此方法的服务的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>
Run Code Online (Sandbox Code Playgroud)
实际死锁发生在一个PurchaseOrderItem记录上,该记录是通过对LoadOrder的加载调用加载的.
如果正在加载的记录被另一个进程锁定,是否会导致死锁?如果是这样 - 添加一个事务包装器,如下面的那个解决问题?
<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>
Run Code Online (Sandbox Code Playgroud)
更新:DataBase团队已在服务器上看到跟踪消息,这些消息似乎表明我们的"只读"进程实际上是自动写入数据库.记录的"UPDATE"命令是在我们从数据库中读取的确切列上执行的.似乎Hibernate会自动将这些记录写回数据库(即使我们没有要求它).这可能解释了为什么会出现僵局.
这可能是因为会话FLUSH或类似的东西?看起来更像解决方案可能是使用带有readOnly的事务包装器...
我们最终确定解决方案是将其包装在只读事务中。
我不清楚为什么,我们根本没有使用设置器(只是读取数据)——数据库中没有任何变化。但由于某种原因,Hibernate 试图重新写回相同的数据,并在另一个进程尝试读取这些记录时导致锁定。
使用只读事务使问题消失!
<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>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9506 次 |
| 最近记录: |