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;
}
}
Навіщо так складно, ти запитаєш?
Ну, по-перше, будь-які зміни бази даних завжди несуть у себе різні і який завжди очевидні наслідки. А по-друге, у даного об'єкта могли бути пов'язані з ним дочірні об'єкти тощо. Тому сценарії видалення часто бувають нетривіальними.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ