Hibernate StaleObjectStateException Проблема вызова слияния - PullRequest
0 голосов
/ 24 апреля 2018

Я пытаюсь протестировать оптимистическую блокировку с помощью аннотации 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 со статусом «NEW». Как только поток извлекает строку со статусом = 'NEW', он обновляет статус строки в таблице на '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;
}

1 Ответ

0 голосов
/ 24 апреля 2018

См. этот вопрос о типе исключения.

Транзакция не откатывается автоматически. Такое исключение никогда не следует перехватывать и продолжать использовать сеанс Hibernate. Причина в том, что сеанс мог быть частично синхронизирован с базой данных, поэтому состояние базы данных может быть несовместимым. Так что пусть исключение будет выброшено за пределы транзакции, где оно будет откатано, и начнется заново с новым сеансом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...