JavaRush /Курсы /Модуль 4. Работа с БД /Удаление объекта

Удаление объекта

Модуль 4. Работа с БД
11 уровень , 4 лекция
Открыта

Удаление с помощью метода remove()

Наконец разберем удаление объекта. В принципе удалять объекты из базы очень просто, но как говориться, есть нюансы. И таких нюансов аж шесть:

  • Удаление с помощью метода remove()
  • Удаление за компанию
  • Удаление по Orphan
  • Удаление с помощью JPQL
  • Удаление через NativeQuery
  • softDeleted()

И начнем мы с самого очевидного решения — вызова метода remove().


User user = new User();
user.setName("Колян");
session.persist(user);  //добавляем объект в базу
session.flush(); 
session.clear();  //закрываем сессию
 
user = (User) session.find(User.class, user.getId() ); //заново получаем объект из базы
session.remove(user);
session.flush(); 
session.clear();  //закрываем сессию
 
//тут объект реально удален.

Реальная операция в базе будет выполнена после вызова метода flush() или закрытия транзакции.

Каскадное удаление

Помнишь, когда мы изучали SQL, то зависимым таблицам можно было прописывать CONSTRAINT. И одна из них записывалась так:


CONSTRAINT ONDELETE REMOVE

Смысл ее был в том, что если у нас есть таблица, которая содержит дочерние сущности, то при уделении сущности-родителя нужно удалить все ее дочки.

Допустим, мы где-то храним персональную информацию пользователя и настроили CONSTRAINT в базе так, чтобы при удалении пользователя эти данные тоже удалялись. Тогда нам нужно просто удалить родительский объект и все дочерние объекты будут удалены на уровне базы:


User user = new User();
UserPrivateInfo info = new UserPrivateInfo();
user.setPrivateInfo(info);
session.persist(user);  //добавляем объект в базу, также в базу сохранится и объект info
session.flush(); 
session.clear();  //закрываем сессию
 
user = (User) session.find(User.class, user.getId() ); //заново получаем объект из базы
session.remove(user);
session.flush(); 
session.clear();  //закрываем сессию
 
//тут объекты user и info реально удалены из базы.

Удаление по Orphan

Также есть еще один тип удаления, который называют удаление по Orphan. Он чем-то похож на предыдущий вариант. Дочерняя сущность удаляется, когда разрывается ее связь с родительской сущностью. При этом родительская сущность обычно не удаляется.

Допустим, у нас есть пользователь, а у него есть список сообщений:


User user = new User();
UserMessage message = new UserMessage();
user.getMessageList().add(message);
session.persist(user);  //добавляем объект в базу, также в базу сохранится и объект message
session.flush(); 
session.clear();  //закрываем сессию
 
user = (User) session.find(User.class, user.getId() ); //заново получаем объект из базы
UserMessage message2 = user.getMessageList().get(0); //получаем сообщение пользователя
user.getMessageList().remove(message2);  //удаляем сообщение из списка
session.flush(); 
session.clear();  //закрываем сессию
 
//тут объект message2 реально удален из базы

Также есть важный нюанс, если мы хотим, чтобы Hibernate реализовывал такое поведение, его нужно явно указать при связывании двух сущностей с помощью аннотаций:


@Entity
public class User {
 
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserMessage> messageList = new ArrayList<UserMessage>();
 
}

Удаление через JPQL

Еще один интересный способ удалить объект – это написать запрос на HQL (или JPQL). Только не забудь в конце вызвать метод executeUpdate(), а не то Hibernate создает read-only транзакцию и никакого удаления у тебя не выйдет.

Пример:


User user = new User();
session.persist(user);  //добавляем объект в базу
session.flush(); 
session.clear();  //закрываем сессию
 
session.createQuery("delete from User where id = :id")
   .setParameter("id", user.getId())
   .executeUpdate();

Изменение в базе никак не изменит существующие Entity-объекты.

Удаление через NativeQuery

Аналогично можно удалить и через вызов NativeQuery.

Пример:


User user = new User();
session.persist(user);  //добавляем объект в базу
session.flush(); 
session.clear();  //закрываем сессию
 
session.createNativeQuery("DELETE FROM user WHERE id = :id")
   .setParameter("id", user.getId())
   .executeUpdate();

Изменение в базе никак не затронет существующие Entity-объекты.

Мягкое удаление

Иногда вместо удаления данных в базе бывает удобно просто пометить их как удаленные. Такие данные могут потом участвовать в различных сценариях. Во-первых, такое удаление легко обратимо – строки можно опять пометить как живые.

Во-вторых, такие удаленные данные полезно “складывать в архив”, ведь бывают случаи, когда поведение сервера регулируется законодательством и тому подобное. Однако, если ты будешь помечать твои данные как удаленные, то только ты будешь знать, что они удалены. Hibernate же по-прежнему будет находить эти данные, а также использовать их при сортировке.

Поэтому создатели Hibernate придумали специальную аннотацию, с помощью которой можно было бы помечать объекты как живые. Пример:


@Entity
@Where(clause = "DELETED = 0") //во всех WHERE будет добавляться “AND DELETED = 0”
public class User {
	// маппинг полей
 
	@Column(name = "DELETED") // если значение в колонке DELETED == 0, то запись жива, если 1 - мертва
	private Integer deleted = 0; 
   
	//геттеры и сеттеры
 
    public void softDeleted() {
    	this.deleted = 1; //помечаем запись как мертвую
    }
}

Чтобы пометить объект как удаленный нужно просто вызвать у него метод softDeleted():


User user = new User();
session.persist(user);  //добавляем объект в базу
session.flush(); 
session.clear();  //закрываем сессию
 
user = (User) session.find(User.class, user.getId() ); //заново получаем объект из базы
user.softDeleted(); //помечаем объект как удаленный
session.flush(); 
session.clear();  //закрываем сессию
 
//больше этот объект не будет находиться через Hibernate
1
Задача
Модуль 4. Работа с БД, 11 уровень, 4 лекция
Недоступна
task1104
Напиши код удаления объекта animalRemove с помощью метода remove(). Запусти программу и убедись, что до удаления объект не был равен null, а после удаления — равен null...
1
Задача
Модуль 4. Работа с БД, 11 уровень, 4 лекция
Недоступна
task1105
Напиши код удаления объекта типа Animal c id = 2 с помощью HQL. Используй методы createQuery() и executeUpdate()...
Комментарии (8)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Fargys1879 Уровень 1
26 декабря 2023
Если не ошибаюсь, то CONSTRAINT ON DELETE REMOVE относится к аннотации @OnDelete.Если не указать явно эту аннотацию, то DDL не сформирует такой констрейнт.И работает в обратную сторону, если удалить дочернюю сущность то удалится родительская через механизм самой БД
Андрей Уровень 37 Expert
4 декабря 2023

session.clear();  //закрываем сессию
Почему никто не обращает внимание на комментарии в коде?

session.clear(); // Очищает сессию но не закрывает
session.close(); // закрывает сессию
Дмитрий Уровень 100 Expert
26 января 2024
Да, очень странно. Как я понимаю, ошибка тут. Всё-таки clear() именно очищает сессию, без разрыва соединения.
Nadir Nadirli Уровень 108 Expert
5 января 2023
строчка 7, должно быть user.setDeleted();
Владислав Уровень 100
22 января 2023
Привет, мне кажется там все правильно написано. Просто у объекта вызывается метод, который называется "softDeleted", он присваивает новое значения для поля "deleted".
Саша И. Уровень 101 Expert
16 марта 2023
Поле deleted имеет тип Integer, поэтому при вызове setDeleted() придётся передать аргумент. Допустимые аргументы только 0 и 1, но что будет, если передать 2? Да и зачем вообще передавать что-то кроме 0 и 1? :) Поэтому здесь всё верно - вызывается softDeleted() без аргументов.
14 мая 2023
Тогда логичнее было сделать, чтобы метод принимал boolean
AnnaVin Уровень 47
17 июня 2023
Soft - мягкий, как раз как название "Мягкое удаление".