Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Создание, чтение, изменение, удаление

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())) — и уже его удаляйте.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.