【问题标题】:Hibernate StaleObjectStateException Issue Calling MergeHibernate StaleObjectStateException 问题调用合并
【发布时间】:2018-10-04 17:35:57
【问题描述】:

我正在尝试使用已添加到实体对象的 JPA 的 @Version 注释测试乐观锁定:

@Version    
@Setter(AccessLevel.NONE)
@Column(name = "VERSION")
private long version; 

当我同时运行 2 个服务器时,我收到一个 StaleObjectStateException

Exception message is : Object of class [com.myPackage.WorkQueue] with identifier [9074]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.myPackage.WorkQueue#9074]

我期待看到 1) OptimisticLockException 发生,2) @transaction 结果被回滚。

用例如下:将条目插入到状态为“新”的 Oracle 数据库表中。一旦线程检索到 status = 'NEW' 的行,它会将 Table 上的行状态更新为 'IN_PROGRESS'。如果另一个事务已成功更新该行,我需要确保任何同时读取同一行的事务失败/回滚。

服务:

@Override
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor=Exception.class, readOnly=false)
public WorkQueue retrieveWorkQueueItemByStatus(WorkQueueStatusEnum workQueueStatus) {
    return workQueueRepository.retrieveWorkQueueItemByStatus(workQueueStatus);
}

实施:

@Override
public WorkQueue retrieveWorkQueueItemByStatus(WorkQueueStatusEnum workQueueStatus) {
    log.debug("Start - Attempting to select a " + workQueueStatus + " workQueue item in retrieveWorkQueueItemByStatus()");  

    try {
        String sql = "SELECT a FROM WorkQueue a WHERE workQueueStatus = :workQueueStatus ORDER BY idWorkQueue ASC";
        TypedQuery<WorkQueue> query = em.createQuery(sql, WorkQueue.class).setParameter("workQueueStatus", workQueueStatus)
        .setFirstResult(0).setMaxResults(1);
        WorkQueue workQueue = (WorkQueue) query.getSingleResult();
        if (workQueue != null) {
            workQueue.setWorkQueueStatus(WorkQueueStatusEnum.IN_PROGRESS);
            WorkQueue updatedWorkQueue = em.merge(workQueue);               
            log.debug("Finish - selected the following workQueue item "+ workQueue.getIdWorkQueue() + " with the Audit Event Key from retrieveWorkQueueItemByStatus() : " + updatedWorkQueue.getAuditEventKey());
            return updatedWorkQueue;
        }
    } catch (IllegalArgumentException iae) {
        log.error("An IllegalArgumentException occured in workQueueRepositoryImpl.retrieveWorkQueueItemByStatus() attempting to execute query : " + sql + ". Exception message is : " + iae.getMessage());
    } catch(Exception ex) {
        log.error("An Exception occured in workQueueRepositoryImpl.retrieveWorkQueueItemByStatus() executing query : " + sql + ". Exception message is : " + ex.getMessage());
    }
    log.debug("Finish - returning null from retrieveWorkQueueItemByStatus()");
    return null;
}

【问题讨论】:

    标签: hibernate jpa locking jpa-2.0


    【解决方案1】:

    请参阅this question 了解异常类型。

    事务不会自动回滚。这种异常永远不应该被捕获并继续使用 Hibernate 会话。原因是会话可能已部分同步到数据库,因此数据库状态可能不一致。因此,让异常在事务之外抛出,并在此回滚,并从新会话重新开始。

    【讨论】:

    • 您是说上面的语法是特定于休眠的,而不是特定于 JPA,因此,我没有得到正确的异常类型吗?为什么事务不会自动回滚?
    • Stefan,我已经从上述实现中删除了 try catch 语句,并在 retrieveWorkQueueItemByStatus() 方法签名中添加了 throws RuntimeException。假设当 Hibernate 抛出 StaleObjectStateException 时事务将回滚,我是否正确?
    • 当事务在抛出异常的时间点回滚对您很重要时,我会检查 Hibernate 代码。通常异常是从一些尝试(使用资源)块中抛出的,并且事务和会话被关闭。这至少是回滚的时间点。
    猜你喜欢
    • 2019-04-04
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多