Я встречаюсь с некоторыми странными поведением в управляемых весной транзакциях. Это приложение Spring MVC. Я привязываю объекты непосредственно к веб-уровню. Я загружаю постоянный объект из базы данных для редактирования, используя следующий код уровня сервиса, который вызывается из метода, аннотированного с помощью @ModelAttribute.Spring JPA Transaction
@Transactional(readOnly = true)
@PreAuthorize("#id == authentication.principal.id or hasRole('ROLE_ADMIN')")
public User findById(Long id) {
return repository.findOne(id);
}
Когда форма отправлена, данные привязаны к этому отдельному объекту. В рамках проверки я запрашиваю базу данных для проверки того, что адрес электронной почты, указанный для пользователя, уникален.
@Transactional(readOnly = true)
public boolean isEmailAddressUnique(String emailAddress, Long userId){
return repository.checkEmailAddressUnique(emailAddress, userId) == 0;
}
На данный момент, перед выполнением этого запроса Hibernate пытается очистить предварительно загруженный отдельностоящий объект, который я не понимаю. Очевидно, что это приводит к исключению, если адрес электронной почты не уникален.
Я использую OpenEntityManagerinViewFilter, однако я бы ожидал, что это должно иметь значение FlushMode NEVER, возможно, нет.
Если я удаляю атрибут @Transactional из isEmailAddressUnique(), то флеш не возникает, и все работает так, как ожидалось, что, я полагаю, решает проблему, однако я хотел бы понять, что здесь происходит.
Любые предложения?
=============
Хорошо, я исследовал дальше. Таким образом, у меня есть OpenEntityManagerInViewFilter с настройками по умолчанию:
Сценарий первый.
[1] MVC контроллер загружает объект пользователя в READONLY транзакции T1 [2] Объект изменен в результате связывания поля MVC [3] второй транзакции работает против таблицы Users в READONLY транзакции Т2. [4] Спящий режим сбрасывает объект, загруженный в T1. [5] Hibernate выдает то запрос
Сценарий 2.
подклассы OEMIVFilter установить FlushMode совершить (по умолчанию автоматически).
Как указано выше, с шагами [4] и [5] отменено, а именно. даже если T2 отмечен как readOnly Hibernate все еще пытается выполнить Flush в конце транзакции. Я мог понять сценарий 1, поскольку readOnly может ссылаться только на текущую транзакцию T2 (и будет пытаться синхронизировать базу данных перед выполнением T2). Однако я ожидал, что в сценарии 2 не будет выпущен флажок.
Подумав об этом немного больше, я полагаю, что имеет смысл, что каждая транзакция привязана к той же сессии спящего режима, а именно: которые связаны с запросом фильтром OEMIV. Это, однако, кажется немного опасным в том, что изменения могут быть сброшены в базу данных без явной перезагрузки и сохранения объекта.OpenSessionViewFilter разрешает указывать singleSession false, который, как мне кажется, относится к проблеме, поскольку каждая транзакция связана с ее собственным сеансом, но я не вижу аналогичного параметра для фильтра OpenEntityManagerInView. –