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

Зачем так сложно, спросишь ты?

Ну, во-первых, любые изменения базы данных всегда несут за собой различные и не всегда очевидные последствия. А во-вторых, у данного объекта могли быть связанные с ним дочерние объекты и т. п. Так что сценарии удаления часто бывают нетривиальными.

undefined
1
Задача
Модуль 4. Работа с БД, 9 уровень, 3 лекция
Недоступна
task0905
Если ранее не подключал зависимости, то подключи их. Для этого используй Alt + Ctrl + Shift + S (в Идее), вкладка Libraries...