Hibernate StaleObjectStateException异常调用合并 [英] Hibernate StaleObjectStateException Issue Calling Merge

查看:98
本文介绍了Hibernate StaleObjectStateException异常调用合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用已添加到我的实体对象中的JPA的@Version批注来测试开放式锁定:

I'm trying to test optimistic locking using JPA's @Version annotation that I've added to my entity object:

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

同时运行2台服务器时,我收到StaleObjectStateException:

When I run 2 servers concurrently, I receive a 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发生回滚.

I was expecting to see 1) an OptimisticLockException to occur and 2) the @transaction to get rolled back as a result.

用例如下:将条目插入状态为"NEW"的Oracle数据库表中.线程检索到状态为'NEW'的行后,它将表上的行状态更新为'IN_PROGRESS'.如果另一个事务成功更新了该行,我需要确保同时读取同一行的所有事务都失败/回滚.

The use case is as follows: Entries get inserted into an Oracle Database Table with a status of 'NEW'. Once a thread retrieves the row with the status = 'NEW', it updates the row's status on the Table to 'IN_PROGRESS'. I need to ensure any transactions reading the same row at the same time fail/rollback if another transaction has successfully updated that row.

服务:

@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会话捕获并继续这种异常.原因是会话可能已经部分同步到数据库,因此数据库状态可能不一致.因此,让该异常被抛出事务之外,然后在该事务回滚,并从一个新的会话开始.

The transaction is not rolled back automatically. This kind of exception should never be caught and continued using the Hibernate session. The reason is that the session could have been been partially synchronized to the database, therefor the database state could be inconsistent. So let the exception be thrown outside of the transaction, where it is rolled back, and start over with a new session.

这篇关于Hibernate StaleObjectStateException异常调用合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆