1. Можливі варіанти статусу об'єкта

Як ти вже, напевно, звернув увагу, коли об'єкт приєднаний до Hibernate, його стан називається Persistent або Managed. Як правильно? Persist чи Managed?

Можна і так, і так. Згідно зі специфікацією JPA, об'єкт має статус Persist, а згідно зі специфікацією Hibernate його стан називається Managed.

У Hibernate робота з базою ведеться через об'єкт типу org.hibernate.Session. Відповідно до JPA, клас має називатися javax.persistence.EntityManager. Насправді великої проблеми тут немає, тому що обидва типи є інтерфейсами.

Інтерфейс org.hibernate.Session оголошено так:


interface Session extends java.lang.AutoCloseable, javax.persistence.EntityManager, HibernateEntityManager, QueryProducer, java.io.Serializable, SharedSessionContract {
 
}

Тому в інтерфейсі Session є всі методи, які є в інтерфейсі EntityManager. Але також є і свої, які дісталися йому від попередніх версій Hibernate, коли ще не було специфікації JPA.

Описується ця вся ситуація ось такою картинкою:

Давай розберемо всі методи, які є у інтерфейсу session, а також нюанси їхньої роботи.

2. Нюанси роботи методу persist()

Під час збереження об'єкта до бази даних потрібно пам'ятати дві речі.

По-перше, збереження об'єкта врешті-решт призведе до виконання однієї з команд SQL: INSERT або UPDATE. По-друге, ці дії відбудуться не одразу після виклику методу об'єкта session, а лише після закриття транзакції.

Давай розглянемо якусь просту ситуацію. Наприклад, у тебе є клас User:


@Entity
public class User {
@Id
@GeneratedValue
    public Integer id;
 
@Columnt(name="user_name")
    public String name;
}

Давай збережемо до бази його об'єкт за допомогою методу persist().


User user = new User();
user.setName("Колян");
session.persist(user);

Завдання цього методу — зберегти новий об'єкт у базі даних. Якщо такого об'єкта ще немає, він додасться до бази через виклик SQL-методу INSERT.

Якщо ж об'єкт вже є в базі, то нічого не станеться. Однак можливий ще й третій випадок — спроба зберегти до бази об'єкт зі статусом Detached. І тут кинеться виняток. Приклад:


User user = new User();
user.setName("Колян");
session.persist(user);
 
session.evict(user); // від'єднуємо об'єкт від сесії
session.persist(user); // Тут кинеться виняток PersistenceException!

3. Нюанси роботи методу save()

Метод save() дістався нинішньому Hibernate від попередніх версій. За своєю суттю він дуже схожий на метод persist(): він також додає новий запис до таблиці за допомогою методу INSERT. Однак він має кілька цікавих нюансів.

По-перше, цей метод повертає значення — нове ID об'єкта. Як ти вже знаєш, зазвичай до додавання в базу об'єктів немає ID, і воно присвоюється вже базою даних. Так ось, метод save() об'єкта session повертає ID, яка була присвоєна об'єкту, що зберігається.

Важливо! Відповідно до специфікації Hibernate, ID може бути будь-який об'єкт, що серіалізується — не тільки число. Це може бути рядок, число, enum — взагалі будь-що, що можна повністю покласти в одну колонку таблиці в базі.

Метод save() має тип результату Serialized, тому його результат потрібно приводити до правильного типу:


User user = new User();
user.setName("Колян");
Integer id = (Integer) session.save(user);

Також метод save() має іншу поведінку у випадку з Detached станом об'єкта. Такий об'єкт він розглядає як новий і додає ще один запис:


User user = new User();
user.setName("Колян");
Integer id = (Integer) session.save(user);
 
session.evict(user); // від'єднуємо об'єкт від сесії
Integer id2 = (Integer) session.save(user);

Змінні id та id2 будуть відрізнятися. У таблиці в базі даних буде додано два записи: по одному для кожної операції save().