Автор оригинала: François Dupire.
1. введение
В этом коротком уроке мы узнаем, как создавать запросы на обновление с помощью Spring Data JPA @Query аннотации . Мы достигнем этого, используя аннотацию @Modifying .
Во-первых, мы освежим нашу память и посмотрим как делать запросы с использованием Spring Data JPA . После этого мы глубоко погрузимся в использование @Query и @Modifying аннотаций. Наконец, мы увидим, как управлять состоянием нашего контекста сохранения при использовании изменяющих запросов.
2. Запрос в Spring Data JPA
Во-первых, давайте вспомним механизмы 3, которые Spring Data JPA предоставляет для запроса данных в базе данных :
- Методы запроса
- @Query аннотация
- Реализация пользовательского репозитория
Давайте создадим класс User и соответствующий репозиторий Spring Data JPA, чтобы проиллюстрировать эти механизмы:
@Entity @Table(name = "users", schema = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private LocalDate creationDate; private LocalDate lastLoginDate; private boolean active; private String email; }
public interface UserRepository extends JpaRepository{}
Механизм методов запроса позволяет нам манипулировать данными, извлекая запросы из имен методов:
ListfindAllByName(String name); void deleteAllByCreationDateAfter(LocalDate date);
В этом примере мы можем найти запрос, который извлекает пользователей по их именам, или запрос, который удаляет пользователей, имеющих дату создания после определенной даты.
Что касается @Query аннотации, она предоставляет нам возможность написать конкретный JPQL или SQL-запрос в @Query аннотации :
@Query("select u from User u where u.email like '%@gmail.com'") ListfindUsersWithGmailAddress();
В этом фрагменте кода мы видим запрос, извлекающий пользователей, имеющих @gmail.com адрес электронной почты.
Первый механизм позволяет нам извлекать или удалять данные. Что касается второго, то он позволяет нам выполнять практически любой запрос. Однако для обновления запросов мы должны добавить @Modifying аннотацию . Это будет темой данного урока.
3. Использование аннотации @Modifying
То @Изменение аннотация используется для повышения @Запрос аннотации для выполнения не только ВЫБИРАТЬ запросы, но и ВСТАВЛЯТЬ , ОБНОВЛЕНИЕ , УДАЛИТЬ , и даже DDL запросы.
Давайте немного поиграем с этой аннотацией и посмотрим, из чего она сделана.
Во-первых, давайте рассмотрим пример запроса @Modifying UPDATE:
@Modifying @Query("update User u set u.active = false where u.lastLoginDate < :date") void deactivateUsersNotLoggedInSince(@Param("date") LocalDate date);
Здесь мы деактивируем пользователей, которые не входили в систему с определенной даты.
Давайте попробуем еще один, где мы удалим деактивированных пользователей:
@Modifying @Query("delete User u where u.active = false") int deleteDeactivatedUsers();
Как мы видим, этот метод возвращает целое число. Это функция Spring Data JPA @Modifying queries, которая предоставляет нам количество обновленных сущностей.
Следует отметить, что выполнение запроса на удаление с помощью @Query работает иначе, чем методы запроса Spring Data Jpa delete By name. Последний сначала извлекает объекты из базы данных, а затем удаляет их один за другим. Таким образом, это означает, что метод жизненного цикла @PreRemove будет вызван для этих сущностей. Однако в первом случае выполняется один запрос к базе данных.
Наконец, давайте добавим столбец deleted в нашу таблицу USERS с запросом DDL :
@Modifying @Query(value = "alter table USERS.USERS add column deleted int(1) not null default 0", nativeQuery = true) void addDeletedColumn();
К сожалению, использование изменяющих запросов оставляет базовый контекст сохранения устаревшим. Однако с этой ситуацией можно справиться. Это тема следующего раздела.
3.1. Результат неиспользования аннотации @Modifying
Давайте посмотрим, что произойдет, если мы не поместим аннотацию @Modifying в запрос на удаление.
По этой причине нам нужно создать еще один метод:
@Query("delete User u where u.active = false") int deleteDeactivatedUsersWithNoModifyingAnnotation();
Обратите внимание на отсутствующую аннотацию!
Когда мы выполняем описанный выше метод, мы получаем исключение Invaliddataaccessapiusagee :
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [delete com.baeldung.boot.domain.User u where u.active = false] (...)
Сообщение об ошибке довольно ясно – запрос Не поддерживается для операций DML .
4. Управление контекстом сохранения
Если изменение запроса изменяет сущности, содержащиеся в контексте сохранения, этот контекст устаревает. Один из способов справиться с этой ситуацией – очистить контекст сохранения . Делая это, мы удостоверяемся, что контекст сохранения будет извлекать сущности из базы данных в следующий раз.
Однако нам не нужно явно вызывать метод clear() в EntityManager . Мы можем просто использовать очистить автоматически свойство из аннотации @Modifying :
@Modifying(clearAutomatically = true)
Таким образом, мы гарантируем, что контекст сохранения будет очищен после выполнения нашего запроса.
Но что, если наш контекст сохранения содержал незаполненные изменения? Поэтому его очистка будет означать удаление несохраненных изменений. К счастью, есть еще одно свойство аннотации, которое мы можем использовать – flushAutomatically :
@Modifying(flushAutomatically = true)
Теперь, EntityManager сбрасывается перед выполнением нашего запроса.
5. Заключение
На этом заканчивается эта короткая статья об аннотации @Modifying . Мы видели, как использовать эту аннотацию для выполнения запросов обновления, таких как INSERT, UPDATE, DELETE, и даже DDL . После этого мы узнали, как управлять состоянием контекста сохранения с помощью свойств clear Автоматически и flushAutomatically .
Как обычно, полный код этой статьи доступен на GitHub .