В одной статье по Hibernate прочитал, что если вы хотите использовать многопоточность, то создавайте новую сессию для каждой CRUD-операции. То есть вот как выглядит, например, операция сохранения в моем DAO-классе:
public void save(User user) {
try (Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession()) {
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
}
}
Но вот незадача. Сегодня наткнулся на еще одну статью, в которой говорят, что описанное выше действие является анти-паттерном. Дословно:
Это анти-паттерн про открытие и закрытие объекта Session на каждую операцию к БД в одном потоке. Это также анти-паттерн в терминах транзакций БД. Группируйте ваши вызовы в одну запланированную последовательность. Также, не делайте авто-коммит транзакции на каждое SQL-выражение. Hibernate выключает, или ожидает, что сервер приложений немедленно выключит режим авто-коммита.
Заместо этого в этой статье предложен Паттерн сессия-на-запрос
, где его описывают как:
Наиболее распространенный паттерн транзакций. Термин “запрос” здесь следует понимать в контексте системы, реагирующей на серии запросов от пользователя/клиента. Веб-приложения является основным примером таких систем, но, конечно, не только они одни. На этапе начала обработки запроса, приложение открывает объект Session, инициирует транзакцию, проводит всю сопутствующую работу с данными, завершает транзакцию и закрывает Session. Суть паттерна – это отношение один-к-одному между транзакцией и сессией.
После этого у меня возник когнитивный диссонанс. Во-первых потому, что оказывается согласно этой статье, раньше я делал не так, создавая сессию для каждой операции, а во-вторых потому, что я не понял, что предполагает второй паттерн. Объясните, что из этого правда, а что ложь? Что использовать, а про что забыть?
Если обратится к документации Hibernate - то по ней сессия-на-операцию официально обьявлена антипаттерном.
Что касается сессии, то сам ее смысл предполагает что вы можете и по возможности должны объединять связанные по смыслу операции в рамках одной или нескольких транзакций в одну сессию. В тоже время ничего плохого нет в том что ваша сессия может содержать лишь одну операцию, если кроме этой операции ничего делать не надо.
Чтобы понять разницу между первым и вторым приведу пример: представьте что существует еще один класс связанный с User, например UserHistory (пусть он будет хранить историю изменения имени пользователя). Мы предполагаем по смыслу что изменяя name в User должен обязательно обновляться и класс UserHistory.
Теперь представим что мы сделали все через operation-per-session. В этом случае у нас будет две разные сессии и две транзакции которые обновят User и UserHistory независимо друг от друга. Проблема возникнет тогда когда одна из транзакций не дойдет (например из за внезапных потерь на сети) что неизбежно приведет к нарушению целостности данных в БД.
И да, при работе с БД не через пулы - крайне ресурсоемко создавать и закрывать соединения с БД при каждом действии.
Действительно как пишется в документации к Hibernate:
The scope of a Hibernate org.hibernate.Session is flexible but you should never design your application to use a new Hibernate org.hibernate.Session for every database operation. Even though it is used in the following examples, consider session-per-operation an anti-pattern
Обратите внимание, что говорится о новой сессии, по сути предлагается использовать текущую сессию, а именно:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//blah-blah
session.getTransaction().commit();
То есть если нет текущей сессии, то создаем, если есть берем текущую.
Создание сессии при каждой операции является антипаттерном, но не потому, что типа в другой сессии будет произведено обновление или там не дойдет до конца транзакция (менеджер транзакций СУБД вполне умеет с такими вещами работать), а из-за стоимости создания сессии - по сути это новый коннект к БД - крайне дорогая и ресурсоемкая операция.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
В универе задали задание сделать сайт с усложненной архитектурой, чтобы был сервер на PHP, который от клиента принимал запросы, потом отправлял...
Нужно чтобы при нажатии на оповещение с определенным текстом открывалась определенная вкладка viewPager, но как это реализовать?
Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском