Создание, чтение, изменение, удаление
CRUD — четыре базовые операции с данными: create, read, update, delete (создать, прочитать, изменить, удалить). В Hibernate каждая из них — один вызов EntityManager, SQL писать не нужно. В этом уроке пройдём все четыре на сущности Post.
Все четыре операции
// src/main/java/com/example/blog/Main.java
package com.example.blog;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Main {
public static void main(String[] args) {
try (EntityManagerFactory emf = Persistence.createEntityManagerFactory("blog")) {
// Создание
Long id = emf.callInTransaction(em -> {
Post post = new Post("Привет, Hibernate", "Моя первая статья");
em.persist(post);
return post.getId();
});
IO.println("Создана статья " + id);
// Чтение
Post post = emf.callInTransaction(em -> em.find(Post.class, id));
IO.println("Прочитана: " + post.getTitle());
// Изменение
emf.runInTransaction(em -> {
Post managed = em.find(Post.class, id);
managed.setTitle("CRUD с Hibernate");
});
// Удаление
emf.runInTransaction(em -> {
Post managed = em.find(Post.class, id);
em.remove(managed);
});
Post deleted = emf.callInTransaction(em -> em.find(Post.class, id));
IO.println("После удаления: " + deleted);
}
}
}callInTransaction работает как runInTransaction, но возвращает результат лямбды. Вывод:
Hibernate: insert into Post (body,title,id) values (?,?,?)
Создана статья 1
Hibernate: select p1_0.id,p1_0.body,p1_0.title from Post p1_0 where p1_0.id=?
Прочитана: Привет, Hibernate
Hibernate: select p1_0.id,p1_0.body,p1_0.title from Post p1_0 where p1_0.id=?
Hibernate: update Post set body=?,title=? where id=?
Hibernate: select p1_0.id,p1_0.body,p1_0.title from Post p1_0 where p1_0.id=?
Hibernate: delete from Post where id=?
Hibernate: select p1_0.id,p1_0.body,p1_0.title from Post p1_0 where p1_0.id=?
После удаления: null| Операция | Метод | SQL |
|---|---|---|
| Создание | persist(post) | insert |
| Чтение | find(Post.class, id) | select ... where id=?; если строки нет, вернёт null |
| Изменение | поменять поле загруженного объекта | update при фиксации |
| Удаление | remove(post) | delete |
remove принимает только объект, загруженный в том же EntityManager, поэтому перед ним стоит find.
merge: изменения извне
В настоящем приложении объект часто приходит из-за пределов транзакции: его загрузили в одном запросе, поправили в форме и прислали обратно. Чтобы сохранить такой объект, используют merge:
// src/main/java/com/example/blog/Main.java
Post post = emf.callInTransaction(em -> em.find(Post.class, 1L));
post.setTitle("Исправлено в форме");
Post merged = emf.callInTransaction(em -> em.merge(post));
IO.println("Объединено: " + merged.getTitle());Hibernate: select p1_0.id,p1_0.body,p1_0.title from Post p1_0 where p1_0.id=?
Hibernate: update Post set body=?,title=? where id=?
Объединено: Исправлено в формеmerge загружает текущую строку, копирует в неё все поля переданного объекта и сохраняет результат. Возвращает он именно эту загруженную копию — дальше работайте с возвращённым объектом, а не с тем, что передали. В чём разница, объясняет следующий урок.
Частая ошибка
Вызов remove для объекта, загруженного в другом, уже закрытом EntityManager, падает:
// src/main/java/com/example/blog/Main.java
emf.runInTransaction(em -> em.remove(post));Exception in thread "main" java.lang.IllegalArgumentException: org.hibernate.DetachedObjectException: Given entity is not associated with the persistence contextЗагрузите объект заново в текущей транзакции — em.remove(em.find(Post.class, post.getId())) — и уже его удаляйте.