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

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

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

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

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

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

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

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

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

4.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;
    }
}

4.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.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;
   	}
}

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

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