Рубрики
Без рубрики

Весенние данные JPA @Изменение аннотации

Создайте запросы DML и DDL в Spring Data JPA, объединив аннотации @Query и @Modifying

Автор оригинала: 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 {}

Механизм методов запроса позволяет нам манипулировать данными, извлекая запросы из имен методов:

List findAllByName(String name);
void deleteAllByCreationDateAfter(LocalDate date);

В этом примере мы можем найти запрос, который извлекает пользователей по их именам, или запрос, который удаляет пользователей, имеющих дату создания после определенной даты.

Что касается @Query аннотации, она предоставляет нам возможность написать конкретный JPQL или SQL-запрос в @Query аннотации :

@Query("select u from User u where u.email like '%@gmail.com'")
List findUsersWithGmailAddress();

В этом фрагменте кода мы видим запрос, извлекающий пользователей, имеющих @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 .