Транзакция создается без аннотации @Transactional

У меня есть метод execute(), который вызывает 2 метода сервиса, который совершает запросы в базу данных. Мне нужно, чтобы на все выполнение данного метода была только 1 транзакция, внутри которой записи были бы заблокированы для других транзакций. Вот пример этого метода, который должен открывать транзакцию:

public class JobService {

    @Autowired
    private RequestService requestService

    @Transactional
    public void execute() {
        List<Request> entitiesForProcessing = 
        requestService.entityListByStatus(requestStatus.CREATED.getCode(), MAX_PROCESSING_ENTITY_COUNT);
        for (Request request: entitiesForProcessing ) {
        //обработка каждой записи
        requestService.saveOrUpdateRequest(request);
    }
}

Метод сервиса, который достает сущности из базы с блокировкой (без аннотации @Transactional):

public List<Request> entityListByStatus(Integer status, int maxResultCount) {
    DetachedCriteria criteria = DetachedCriteria.forClass(Request.class);
    criteria.add(Restrictions.eq("status", status));
    criteria.setLockMode(LockMode.PESSIMISTIC_WRITE);
    LOGGER.info("Select сущностей Request по статусу {}", status);
    return dao.listByCriteria(criteria, maxResultCount);
}

Метод выше действительно блокирует записи на все время выполнения метод execute(), но метод saveOrUpdateRequest() сам открывает транзакцию, несмотря на отсутствие аннотации. Это приводит к тому, что новая транзакция не может обновить записи, так как они заблокированы другой транзакцией. Метод сервиса, который не должен открывать транзакцию , но открывает:

public class RequestService {

    @Autowired
    private Dao dao;

    public void saveOrUpdateRequest(Request request) {
        try {
            dao.saveOrUpdate(gibddRequest);
        } catch (RuntimeException e) {   
            LOGGER.error(e.getMessage());
        }
    }
}

Метод dao использует Hibernate для доступа к базе данных:

public void saveOrUpdate(Object entity) {
    Session currentSession = getCurrentSession();
    currentSession.saveOrUpdate(entity);
}

Я пробовал все возможные параметры propagation, но транзакция все равно открывается. При этом никаких исключений не происходит. Так же, я попробовал выбирать записи без блокировки, в таком случае метод saveOrUpdateRequest() может обновить записи, но только если в параметры аннотации указать @Transactional(propagation = Propagation.REQUIRES_NEW). Как мне сделать так, чтобы была только 1 изолированная транзакция, созданная методом execute()?


Ответы (1 шт):

Автор решения: Ruslan Pavlov

Оказалась, что проблема была в том, что Spring выполнял все в одной транзакции, но откатывал из-за возникшего RuntimeException, из за чего изменения не фиксировались. При возникновении RuntimeException Spring отмечает транзакцию как rollback-only и откатывет ее, даже если вы отловите это исключение. Одно из решений описано здесь

https://habr.com/ru/articles/725064/

В моем случае помогло устранение причины этого исключения

→ Ссылка