应该如何在遗留 Spring Hibernate 应用程序中处理 javax.persistence.OptimisticLockException

问题描述 投票:0回答:1

我们有一个遗留的 Spring Hibernate 应用程序,它利用基于 XML 的 Hibernate 配置。间歇性地,当并发调用一个操作时,我们会遇到

javax.persistence.OptimisticLockException:批量更新返回 更新 [0] 中的意外行计数;实际行数:0;预期的: 1.

据我所知,如果多个事务访问同一个表,那么在向数据库发出并发请求时,我们通常会遇到 OptimisticLockException。然而,就我而言,它是在单个事务中。让我分享映射和代码以更好地解释。

用户.hbm.xml:

<class lazy="false" name="UserBO" table="USER">           
    <id name="id" type="java.lang.Long" column="ID" unsaved-value="null">              
        <generator class="native"/>
    </id>
    <many-to-one name="addressSet" column="ADDRESS_SET" class="AddressSetDO"/> 
</class>

地址集.hbm.xml:

<class lazy="false" name="AddressSetDO" table="ADDRESS_SET_TABLE">
    <id name="id" type="java.lang.Long" column="ID" unsaved-value="null">            
        <generator class="native"/>
    </id>
    <version column="HIB_VERSION" name="HibVersion"/>      
    <set name="address" inverse="true" lazy="false" cascade="delete">            
        <key column="ADDRESS_SET_ID" />
        <one-to-many class="AddressDO"/>                 
    </set>       
</class>

地址.hbm.xml:

    <class lazy="false" name="Address" table="ADDRESS">     
        <id name="id" type="java.lang.Long" column="ID" unsaved-value="null">           
            <generator class="native"/>
        </id>        
        <version column="HIB_VERSION" name="HibVersion"/>
<many-to-one name="addressSet" not-null="true" class="AddressSetDO" index="ADDRESSSET" inverse="true" >      
            <column name="ADDRESS_SET_ID"  not-null="true" /> </many-to-one>  </class>
   

代码流程:从主类来看(由于逻辑复杂,我们尝试在事务内部调用3次save方法): 服务等级:

Transaction start
// code logic
dao.save(data);
// code logic
dao.save(data);
// code logic
dao.save(data);
Transaction end

Dao类(即使我们有映射,我们还是手动保存映射表):

 saveOrUpdate(userBo); //userBo
    if(userBo.getAddressSet() != null)
        saveOrUpdate(userBo.getAddressSet()); //AddressSet
        saveOrUpdate(userBo.getAddressSet().getAddress()); //Address

我的 saveOrUpdate 代码是:

void saveOrUpdate(obj) {
    try {
        hibernateSession().saveOrUpdate(obj);
        checkReadOnlySession();
        hibernateSession().flush();
    } catch (PersistenceException e) {
        throw e;
    }
}

注意:这个逻辑已经存在很多年了,试图改变它会带来巨大的风险。

现在,如果我继续使用单独的数据调用该功能,我会间歇性地遇到 saveOrUpdate(userBo.getAddressSet()) 的以下问题:

javax.persistence.OptimisticLockException:批量更新返回 更新 [0] 中的意外行计数;实际行数:0;预计:1 在 org.hibernate.internal.ExceptionConverterImpl.wrapStaleStateException(ExceptionConverterImpl.java:212) 在 org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:86) 在 org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) 在 org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) 在 org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1434) 在 org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1414)

但是当我启用 show_sql 查看脚本时,问题不会发生。另外,当我将持久性延迟 10 毫秒时,我无法重现该问题:

Thread.sleep(10);
saveOrUpdate(userBo.getAddressSet());

这让我相信问题不在于多个事务修改相同的数据,而在于事务中对同一个表的多次调用。

问题

处理这种情况的最佳方法是什么? 我认为这应该涉及重试该机制。在这种情况下,最好的方法是什么?我们可以在同一事务中重试(第一种方法)或从新事务重试(意味着从头开始重试操作)吗?

如有任何帮助,我们将不胜感激。

spring hibernate jpa concurrentmodification
1个回答
0
投票

重试业务事务作为 OptimisticLockException 的通用恢复策略仅适用于简单的情况。复杂的用例通常需要合并,因此用户界面需要调整

© www.soinside.com 2019 - 2024. All rights reserved.