Транзакция создается без аннотации @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 шт):
Оказалась, что проблема была в том, что Spring выполнял все в одной транзакции, но откатывал из-за возникшего RuntimeException, из за чего изменения не фиксировались. При возникновении RuntimeException Spring отмечает транзакцию как rollback-only и откатывет ее, даже если вы отловите это исключение. Одно из решений описано здесь
https://habr.com/ru/articles/725064/
В моем случае помогло устранение причины этого исключения