Почему мы должны использовать @Modifying аннотацию для запросов в Data Jpa
например, у меня есть метод в моем интерфейсе CRUD, который удаляет пользователя из базы данных:
public interface CrudUserRepository extends JpaRepository<User, Integer> {
@Transactional
@Modifying
@Query("DELETE FROM User u WHERE u.id=:id")
int delete(@Param("id") int id, @Param("userId") int userId);
}
Этот метод будет работать только с аннотацией @Modification. Но в чем здесь нуждается аннотация? Почему can not spring анализирует запрос и понимает, что это модифицирующий запрос?
Ответы
Ответ 1
Это вызовет запрос, аннотированный к методу, как обновление запроса, а не его выбор. Поскольку EntityManager может содержать устаревшие объекты после выполнения модифицирующего запроса, мы автоматически очищаем его (подробности см. В JavaDoc of EntityManager.clear()). Это позволит эффективно удалить все незаполненные изменения, все еще ожидающие рассмотрения в EntityManager. Если вы не хотите, чтобы EntityManager был очищен автоматически, вы можете установить @Modifying аннотацию clearAutomatically атрибут false,
для более подробной информации вы можете перейти по этой ссылке: -
http://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/reference/html/jpa.repositories.html
Ответ 2
CAUTION!
Использование @Modifying(clearAutomatically=true)
приведет к удалению любых ожидающих обновлений для управляемых прав доступа в контексте постоянства. Весенние состояния следующие:
Это вызывает запрос, аннотированный методу как обновление запрос вместо выбора. Поскольку EntityManager может содержать устаревшие сущности после выполнения модифицирующего запроса, мы делаем не очищать автоматически (см. JavaDoc EntityManager.clear() для деталей), так как это эффективно отбрасывает все не очищенные изменения все еще в ожидании в EntityManager. Если вы хотите, чтобы EntityManager очищаться автоматически, вы можете установить аннотации @Modifying атрибут clearAutomatics для true.
К счастью, начиная с Spring Boot 2.0.4.RELEASE
Spring Data добавлен флаг flushAutomatically
(https://jira.spring.io/browse/DATAJPA-806) для автоматической очистки любых управляемых объектов в контексте постоянства перед выполнением ссылки на проверку модифицирующего запроса https://docs.spring.io/spring-data/jpa/docs/2.0.4.RELEASE/api/org/springframework/data/jpa/repository/Modifying.html#flushAutomatically
Поэтому самый безопасный способ использовать @Modifying
:
@Modifying(clearAutomatically=true, flushAutomatically=true)
Что произойдет, если мы не используем эти два флага?
Рассмотрим следующий код:
repo {
@Modifying
@Query("delete User u where u.active=0")
public void deleteInActiveUsers();
}
Сценарий 1, почему flushAutomatically
service {
User johnUser = userRepo.findById(1); // store in first level cache
johnUser.setActive(false);
repo.deleteInActiveUsers();// BAM it won't delete JOHN
// JOHN still exist since john with active being false was not
// flushed into the database when @Modifying kicks in
}
Сценарий 2, почему clearAutomatically
Далее рассмотрим, что johnUser.active уже ложен
service {
User johnUser = userRepo.findById(1); // store in first level cache
repo.deleteInActiveUsers(); // john is deleted now
System.out.println(userRepo.findById(1).isPresent()) // TRUE!!!
System.out.println(userRepo.count()) // 1 !!!
// JOHN still exist since in this transaction persistence context
// was not cleared upon @Modifying query execution, John will still
// be fetched from 1st level cache
// 'clearAutomatically' takes care of doing the
// clear part on the object being modified
}
Так что если - в той же транзакции - вы играете с измененными объектами до или после строки, в которой @Modifying
использует clearAutomatically
& flushAutomatically
если нет, то вы можете пропустить, используя эти флаги
Ответ 3
Запросы, требующие аннотации @Modifying
включают @Modifying
INSERT, UPDATE, DELETE и DDL.
Добавление аннотации @Modifying
указывает, что запрос не для запроса SELECT.