1. Транзакції та цілісність бази даних

Звичайний режим роботи бази даних — це коли до неї щохвилини приходять тисячі запитів від сотень різних клієнтів. За такої умови часто виникають ситуації, коли до тих самих даних йде звернення з різних запитів.

Рідше, але, знов-таки, час від часу виникають ситуації, коли один запит читає певний рядок, а інший запит у цей час змінює його. Уяви, що буде, якщо хтось прочитає рядок, який змінено лише наполовину? Нічого хорошого.

Цю проблему вирішують декількома способами. По-перше, можна просто лочити рядок, який змінюється. І для читання, і запису. Цей спосіб працює, але швидкість бази сильно страждає.

Другий спосіб — це лочити рядок лише на запис. А проте все одно буде проблема, коли хтось спробує прочитати частково змінений рядок. Висновок — не повинно бути ситуації, коли рядок частково змінено.

Тому вигадали третій спосіб — транзакції. Транзакція — це група дій, які виконуються або всі разом, або жодна з них. Не може бути ситуації, коли частина дій виконалася, а друга — ні. Якщо не вдається внести всі зміни, то всі вже внесені відкочуються назад.

Будь-який сучасний SQL-сервер дозволяє змінювати дані лише у транзакціях. Ти відкриваєш транзакцію, вносиш будь-які зміни до будь-якої кількості таблиць, і комітиш транзакцію. Потім SQL-сервер намагається внести зміни. Якщо все просто добре, то вони додадуться до загальної бази даних. Якщо були проблеми, всі зміни скасовуються.

Hibernate також використовує цю парадигму. Саме тому у попередній лекції ми побачили, під час спроби зберегти об'єкт Employee до бази спочатку відкривалася транзакція, а після збереження — комітилася.

Ми ще розберемо цю тему детальніше, а наразі просто знай, навіщо транзакції потрібні і де вони зазвичай використовуються.

2. Отримання об'єктів

Якщо Hibernate виконує запит на отримання даних, явно транзакцію відкривати не потрібно. Hibernate сам це зробить, якщо вважатиме за потрібне: у нього є його налаштування, а також налаштування SQL-сервера.

Ми з тобою розберемо способи роботи з базою даних. І найпростіший з них — це отримання об'єкта за його ID. Для цього потрібно використовувати метод get() в об'єкті session. Загальний вигляд такого запиту:


Клас ім'я = session.get(Клас.class, ID);
        

Приклад:


public User getUserById(Integer id) {
    try (Session session = sessionFactory.openSession()) {
        User user = session.get(User.class, id);
        return user;
    }
}

3. Збереження (додавання) об'єктів

Якщо ти хочеш зберегти свій об'єкт у базі даних, то на рівні SQL виконається запит INSERT. Тому твої дії слід виконувати у вигляді окремої транзакції. До того ж, для збереження краще використовувати метод persist() об'єкта session.

Загальний вигляд такого запиту:


session.persist(Об'єкт);
        

Метод persist() змінює не лише базу, а й сам об'єкт. Вся справа в тому, що коли ми додаємо об'єкт до бази, то до додавання цього об'єкта ще немає свого ID. Ну, зазвичай так відбувається, хоч бувають нюанси. А після додавання до об'єкту ID вже є.


public boolean saveUser(User user) {
    try (Session session = sessionFactory.openSession()) {
            Transaction transaction = session.beginTransaction();
            session.persist(user);
            transaction.commit();
            return true;
    }
    catch() {
    return false;
   }
}

Також об'єкт Session має метод save(), який виконує аналогічну функцію. Просто метод save() — це старий стандарт Hibernate, а метод persist() — це стандарт JPA.

4. Видалення об'єктів

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

Загальний вигляд такого запиту:


session.remove(Об'єкт);
        

І, звісно, напишемо код з прикладом:


public boolean removeUser(User user) {
    try (Session session = sessionFactory.openSession()) {
            Transaction transaction = session.beginTransaction();
            session.remove(user);
            transaction.commit();
            return true;
    }
    catch() {
    return false;
   }
}

Навіщо так складно, запитаєш ти?

Ну, по-перше, будь-які зміни бази даних завжди несуть за собою різні та не завжди очевидні наслідки. А по-друге, у цього об'єкта могли бути пов'язані з ним дочірні об'єкти тощо. Тому сценарії видалення часто бувають нетривіальними.