Перейти к содержимому

Как использовать одну сессию hibernate configuration java

  • автор:

Hibernate — Сессии

Сессия используется для получения физического соединения с базой данных. Объект Session является легким и предназначен для реализации каждый раз, когда необходимо взаимодействие с базой данных. Постоянные объекты сохраняются и извлекаются через объект Session.

Объекты сеанса не должны оставаться открытыми в течение длительного времени, потому что они обычно не являются потокобезопасными, и их следует создавать и уничтожать по мере необходимости. Основная функция Session — предлагать, создавать, читать и удалять операции для экземпляров классов сопоставленных сущностей.

Экземпляры могут существовать в одном из следующих трех состояний в данный момент времени —

  • временный — новый экземпляр постоянного класса, который не связан с сеансом и не представлен в базе данных, а значение идентификатора не считается временным в Hibernate.
  • persistent — вы можете сделать временный экземпляр постоянным, связав его с сеансом. Постоянный экземпляр имеет представление в базе данных, значение идентификатора и связан с сеансом.
  • detached — после того, как мы закроем Hibernate Session, постоянный экземпляр станет отдельным экземпляром.

временный — новый экземпляр постоянного класса, который не связан с сеансом и не представлен в базе данных, а значение идентификатора не считается временным в Hibernate.

persistent — вы можете сделать временный экземпляр постоянным, связав его с сеансом. Постоянный экземпляр имеет представление в базе данных, значение идентификатора и связан с сеансом.

detached — после того, как мы закроем Hibernate Session, постоянный экземпляр станет отдельным экземпляром.

Экземпляр Session является сериализуемым, если его постоянные классы сериализуемы. Типичная транзакция должна использовать следующую идиому —

Session session = factory.openSession(); Transaction tx = null; try  tx = session.beginTransaction(); // do some work . tx.commit(); > catch (Exception e)  if (tx!=null) tx.rollback(); e.printStackTrace(); > finally  session.close(); >

Если сеанс вызывает исключение, транзакция должна быть откатана, а сеанс должен быть отменен.

Методы интерфейса сеанса

Существует несколько методов, предоставляемых интерфейсом Session , но я собираюсь перечислить только несколько важных методов, которые мы будем использовать в этом руководстве. Вы можете проверить документацию Hibernate для получения полного списка методов, связанных с Session и SessionFactory .

Транзакция beginTransaction ()

Начните единицу работы и верните связанный объект транзакции.

void cancelQuery ()

Отмените выполнение текущего запроса.

void clear ()

Полностью очистить сессию.

Соединение закрыто ()

Завершите сеанс, освободив соединение JDBC и очистив.

Критерии createCriteria (Класс persistentClass)

Создайте новый экземпляр Criteria для данного класса сущности или суперкласса класса сущности.

Критерии createCriteria (String entityName)

Создайте новый экземпляр Criteria для данного имени объекта.

Сериализуемый getIdentifier (Объектный объект)

Вернуть значение идентификатора данного объекта, связанного с этим сеансом.

Запрос createFilter (Коллекция объектов, String queryString)

Создайте новый экземпляр Query для данной коллекции и строку фильтра.

Запрос createQuery (String queryString)

Создайте новый экземпляр Query для заданной строки запроса HQL.

SQLQuery createSQLQuery (String queryString)

Создайте новый экземпляр SQLQuery для данной строки запроса SQL.

void delete (объектный объект)

Удалите постоянный экземпляр из хранилища данных.

void delete (String entityName, Object object)

Удалите постоянный экземпляр из хранилища данных.

Сеанс get (String entityName, Serializable id)

Вернуть постоянный экземпляр указанного именованного объекта с указанным идентификатором или значение NULL, если такого постоянного экземпляра нет.

SessionFactory getSessionFactory ()

Получить фабрику сеансов, которая создала этот сеанс.

void refresh (объектный объект)

Перечитайте состояние данного экземпляра из базовой базы данных.

Транзакция getTransaction ()

Получить экземпляр транзакции, связанный с этим сеансом.

логическое isConnected ()

Проверьте, подключен ли сеанс в данный момент.

логическое isDirty ()

Содержит ли этот сеанс какие-либо изменения, которые должны быть синхронизированы с базой данных?

логическое isOpen ()

Проверьте, открыт ли сеанс.

Сериализуемое сохранение (объектный объект)

Сохраните данный временный экземпляр, сначала назначив сгенерированный идентификатор.

void saveOrUpdate (Объектный объект)

Сохраните (Object) или обновите (Object) данный экземпляр.

void update (Объектный объект)

Обновите постоянный экземпляр с помощью идентификатора данного отдельного экземпляра.

void update (String entityName, Object object)

Обновите постоянный экземпляр с помощью идентификатора данного отдельного экземпляра.

Hibernate Configuration

JavaTpoint

As Hibernate can operate in different environments, it requires a wide range of configuration parameters. These configurations contain the mapping information that provides different functionalities to Java classes. Generally, we provide database related mappings in the configuration file. Hibernate facilitates to provide the configurations either in an XML file (like hibernate.cfg.xml) or properties file (like hibernate.properties).

An instance of Configuration class allows specifying properties and mappings to applications. This class also builds an immutable SessionFactory.

We can acquire the Configuration class instance by instantiating it directly and specifying mappings in the configuration file. Use the addResource() method, if the mapping files are present in the classpath.

Let’s see an example to provide the configurations in XML file and properties file.

XML Based Configuration

Properties File Configuration

Properties of Hibernate Configuration

Hibernate JDBC Properties

Property Description
hibernate.connection.driver_class It represents the JDBC driver class.
hibernate.connection.url It represents the JDBC URL.
hibernate.connection.username It represents the database username.
hibernate.connection.password It represents the database password.
Hibernate.connection.pool_size It represents the maximum number of connections available in the connection pool.

Hibernate Datasource Properties

Property Description
hibernate.connection.datasource It represents datasource JNDI name which is used by Hibernate for database properties.
hibernate.jndi.url It is optional. It represents the URL of the JNDI provider.
hibernate.jndi.class It is optional. It represents the class of the JNDI InitialContextFactory.

Hibernate Configuration Properties

Property Description
hibernate.dialect It represents the type of database used in hibernate to generate SQL statements for a particular relational database.
hibernate.show_sql It is used to display the executed SQL statements to console.
hibernate.format_sql It is used to print the SQL in the log and console.
hibernate.default_catalog It qualifies unqualified table names with the given catalog in generated SQL.
hibernate.default_schema It qualifies unqualified table names with the given schema in generated SQL.
hibernate.session_factory_name The SessionFactory interface automatically bound to this name in JNDI after it has been created.
hibernate.default_entity_mode It sets a default mode for entity representation for all sessions opened from this SessionFactory
hibernate.order_updates It orders SQL updates on the basis of the updated primary key.
hibernate.use_identifier_rollback If enabled, the generated identifier properties will be reset to default values when objects are deleted.
hibernate.generate_statistics If enabled, the Hibernate will collect statistics useful for performance tuning.
hibernate.use_sql_comments If enabled, the Hibernate generate comments inside the SQL. It is used to make debugging easier.

Hibernate Cache Properties

Property Description
hibernate.cache.provider_class It represents the classname of a custom CacheProvider.
hibernate.cache.use_minimal_puts It is used to optimize the second-level cache. It minimizes writes, at the cost of more frequent reads.
hibernate.cache.use_query_cache It is used to enable the query cache.
hibernate.cache.use_second_level_cache It is used to disable the second-level cache, which is enabled by default for classes which specify a mapping.
hibernate.cache.query_cache_factory It represents the classname of a custom QueryCache interface.
hibernate.cache.region_prefix It specifies the prefix which is used for second-level cache region names.
hibernate.cache.use_structured_entries It facilitates Hibernate to store data in the second-level cache in a more human-friendly format.

Hibernate Transaction Properties

Property Description
hibernate.transaction.factory_class It represents the classname of a TransactionFactory which is used with Hibernate Transaction API.
hibernate.transaction.manager_lookup_class It represents the classname of a TransactionManagerLookup. It is required when JVM-level caching is enabled.
hibernate.transaction.flush_before_completion If it is enabled, the session will be automatically flushed during the before completion phase of the transaction.
hibernate.transaction.auto_close_session If it is enabled, the session will be automatically closed during the after completion phase of the transaction.

Other Hibernate Properties

Property Description
hibernate.connection.provider_class It represents the classname of a custom ConnectionProvider which provides JDBC connections to Hibernate.
hibernate.connection.isolation It is used to set the JDBC transaction isolation level.
hibernate.connection.autocommit It enables auto-commit for JDBC pooled connections. However, it is not recommended.
hibernate.connection.release_mode It specifies when Hibernate should release JDBC connections.
hibernate.current_session_context_class It provides a custom strategy for the scoping of the «current» Session.
hibernate.hbm2ddl.auto It automatically generates a schema in the database with the creation of SessionFactory.

Next Topic Hibernate Tutorial

Youtube

For Videos Join Our Youtube Channel: Join Now

Feedback

  • Send your Feedback to [email protected]

Hibernate Best Practices для начинающих

В данной статье я не ставлю цель подробно описать Hibernate, такого материала полно в сети. Это скорее справочник, в который можно заглянуть и увидеть возможные проблемные места и их решение, который позволит вам не допустить грубых ошибок при использовании Hibernate. Статья рассчитана на читателя уже знакомого с Hibernate и Spring.

Дисклеймер: я не претендую на полноту необходимых действий, ни на их уникальность, если я что-то упустил или исказил, комментарии приветствуются.

Уникальный идентификатор сущности

Начнем с самого очевидного, — с определения сущности. Всегда задавайте уникальный идентификатор (далее id) для всех сущностей, и желательно что бы это было какое нибудь число, например, у вас есть сущность account у которого есть уникальное поле email вам может показаться что данное поле может выступать в качестве id, и поначалу это может оказаться вполне рабочим решением. Но если вкратце, оно не идеально и в будущем может наложить некоторые ограничения на приложение, к тому же по производительности могут возникнуть вопросы.

Уникальный идентификатор

И так, мы определились что id будет целочисленным, далее на сцену выходи вопрос генерации этого id. В случае если СУБД поддерживает тип SEQUENCE(автоинкремент) то всегда предпочтительно выбирать именно его, в некоторых случаях это позволяет сильно повысить производительность системы.

К примеру, если у вас 5 операций вставки новых общностей, Spring Data или сам Hibernate могут быть достаточно умны, что бы поместить из в так называемый Batch и отдать их в СУБД за один раз, но для этого id новых записей надо знать заранее, вот тут то и вступает в игру тот самый автоинкремент, запросив текущее значение счетчика, не трудно догадаться какие id будут у всех пяти записей.

Автоинкремент

Equals и HashCode методы

Всегда ли нужно определять эти два метода, ответ нет, в среднем случае приложению достаточно дефолтных реализаций. Но так же есть и те случаи кода требуется кастомная реализация, т. к. это может существенно увеличить производительность приложения, либо ухудшить, в случае если вы допустили ошибку.

Буде внимательны при выборе полей кандидатов в Equals и HashCode, это критично если ваши сущности будут храниться в коллекции типа Set или Map, либо вам приходится работать с detached объектами. В основном рекомендуют использовать уникальный идентификатор и/или так называемые «натуральные ключи», т. е. Поле однозначно идентифицирующее объект и которое является уникальным.

Избегайте использования @Data и @ToString аннотаций Lombok. Обе эти аннотации использую все поля объектов по умолчанию, что может послужить причиной проблем. При большом желании, можно использовать @ToString, главное не забывайте исключить LAZY поля вышей сущности из обработки при помощи @ToString.Exclude.

@OneToMany(mappedBy = "account", cascade = CascadeType.ALL) @ToString.Exclude private Set relatedPlatforms = new HashSet<>();

Обработка исключений

В случае если вы вдруг используете голый Hibernate, то никогда не обрабатывайте исключение брошенное Jdbc как recoverable, т. е. не пытайтесь продолжать транзакцию, просто откатите её и закройте EntityManager. Иначе Hibernate не гарантирует актуальность загруженных данных!

Если же вы используете Spring Data, то можете быть спокойны, он позаботился об этом за вас.

Обработка исключений

Двухсторонние отношение сущностей

Как вы знаете в Hibernate существуют два типа отношений между сущностями, одно и двустороннее. Не вникая глубоко в детали, скажу что желательно всегда использовать двустороннее, если вы конечно на 100 % уверены, что обратная связи вам никогда не понадобится, то и одностороннее сойдет. Разница между ними не сильно большая (если все сделать грамотно), а пользы гораздо больше от двусторонней.

И так, как же это сделать грамотно? Тут все просто, дабы Hibernate создал именно двустороннее отношение (а не два односторонних) нужно уточнить, какая из сторон является владельцем отношений, а какая является обратной стороной. В этом нам поможет атрибут mappedBy. Он указывается в аннотации, которая находится на противоположной стороне отношения и указывает на владельца.

Двухсторонние отношение сущностей

Так же в рамках данного топика хотел бы заострить ваше внимание на том как я описываю связь в самой сущности, а конкретно:

@OneToMany(mappedBy = "platform", cascade = ) private Set statuses = new HashSet<>();

Хорошей привычкой является инициализация коллекции, иногда может спасти вас от неприятного NullPointerException, либо от постоянной проверки на null коллекции. Так же, вы можете заметить что вместо List, я использую Set, данный трюк может помочь где-то выиграть в ресурсах (при условии что Equals и HashCode переопределены), хотя и List вполне справляется.

Ленивая загрузка

В продолжение темы отношений между сущностями, в зависимости от типа отношений, Hibernate применяет LAZY или EAGER тип загрузки связанных сущностей. Если у вас нет особой причины для обратного, то убедитесь что выставлен тип LAZY.

Параметризованные запросы

Если вдруг вам случается писать JPQL или Native запросы, не забывайте передавать критерии поиска через параметры, никогда не пишите их на прямую в запросе, т.к. это создаёт уязвимость для атаки SQL injection

Параметризованные запросы

Кэш второго уровня

Это очень полезная фитча Hibernate. На этапе изучения фреймворка, этому не уделяется много внимания, да и в принципе маленький проект может вполне существовать без кэша второго уровня. Но если вы метите в Enterprise разработку, ну или просто пилите проект с более или менее серьезной нагрузкой то обязательно ознакомитесь с этим механизмом. Тут требуется тонкая настройка, тема эта обширная и цена ошибки здесь высока. По этому, пока вы в начале своего пути и еще совсем не «волшебник», вы можете применить как минимум «безопасный» подход, который темнее менее так же эффективен и может быть вполне достаточным для проекта. Безопасность метода заключается в том, что работать мы будем только со статическими сущностями, т. е. кандидаты в кэш второго уровня, это те сущности которые не будут меняться в вашем приложении, они либо создаются, либо удаляются. При таком раскладе у вас меньше шансов ошибиться.

Hibernate не содержит реализации данной фитчи, по этому вам придется использовать сторонние реализации, коих множество, я использую Ehcache 3. Так же что бы подружить Hibernate 5 с Ehcache 3 необходимо подключить Hibernate-jcache зависимость.

Необходимые зависимости

После подключения зависимостей необходимо указать Spring что с ними надо работать, а в частности задать свойства jpa persitence sharedCache и hibernate cache.

Файл свойств приложения

Далее выбранную сущность кандидат в кэш необходимо пометить тремя аннотациями @Cacheable @Cache и @Immutable

Кэшируемая сущность

Вот и все, вы реализовали потокобезопасный кэш второго уровня! Остаются еще такие тонкости как настройка времени жизни объектов в кэше, размер кэша и т. д. Тем не менее на дефолтных настройках это тоже работает. Начните это использовать, ну а далее погружайтесь в детали, Гугл вам в помощь 😉

Аннотация @Column и @Table

При использовании данных аннотаций так же является хорошей практикой всегда задавать имя поля/таблицы. Если вы этого не сделаете, то Hibernate заделает это за вас и имя может не всегда соответствовать ожиданиям.

Имена полей и таблиц

Количество загруженных сущностей

Это не очень насущная проблема и вы скорее с ней не столкнетесь, но я считаю, что вам стоит о ней знать. Дело в том что управляемые сущности не только занимают память, но еще потребляют процессорное время. Hibernate периодически проверяет состояние загруженных объектов на соответствие в базе данных, за это отвечает так называемый dirty checking. В рамках много пользовательского приложения это может быть значимой нагрузкой. Здесь очень полезна ленивая загрузка.

Проблема N+1 Select

Универсального решения этой проблемы нет, многое зависит от проекта. Я опешу самые явные случаи.

При получении сущности или списка общностей, Hibernate сделает один select и все бы ничего, но если данные сущности имеют EAGER отношения (ManyToOne и OneToOne по умолчанию EAGER) то для каждого из них будет сделан дополнительный select!

Выходом из этой ситуации может быть изменение дефолтного EAGER на LAZY.

@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "status") private StatusEntity status;

Все же это решение подходит не всегда, допустим вы получаете список сущностей AccountEntiy, который содержит в себе связь с StatusEntity, и вам необходим проверить статус каждой сущности (разумеется вы делаете это в рамках одной транзакции, иначе вы получите LazyInitializationException), это приведет снова к той же проблеме, при обращении к статусу каждой сущности Hibernate сделает отдельный select, и вот проблема снова вернулась.

В этом случае проблему поможет решить инструкция JOIN FETCH, которая укажет Hibernate что связанные сущности тоже надо загрузить, вот пример JPQL запроса:

select account from AccountEntity account left join fetch account.status

В этом решении есть одна проблема, если вдруг список сущностей очень сильно вырастит. Представьте что количество записей AccountEntity равно пятидесяти тысячам, загрузить такое количество общностей будет не легко, а тут в нагрузку еще пятидесяти тысяч StatusEntity, это ужу совсем непростая задача. Дабы избежать этих трудностей нужно вернуться к схеме с ленивой загрузкой, в итоге система за раз загрузит только AccountEntity, что уменьшит нагрузку, но в то же время вернет проблему N+1 запросов. Без паники, выход найдется и из этой ситуации, так сказать «золотая середина».

Стратегия загрузки Batch Fetching позволяет получать связанные сущности не одиночными запросами, а пакетно. Размер пакета задается аннотацией @BatchSize.

@ManyToOne @JoinColumn(name = "status") @BatchSize(size = 10) private StatusEntity status;

Использование данной аннотации с параметром «size=10» приведет к тому, что Hibernate за раз будет загружать ту сущность, что вы хотите прочитать и девять следующих по порядку.

Заключение

И так, я показал вам подводные камни и как их можно обходить. Но ни одно решение не является универсальным, я призываю вас не заниматься капипастом, а вникать в суть проблемы. Как я и написал выше, это справочник с примерами, а не подробная инструкция.

На примере уникального идентификатора, я покажу почему в вашем конкретном случае решение приведенное в данной статье может быть не самым эффективным.

Давайте представим что на вашем проекте вы используете в качестве базы данных PostgreSQL и вы решили задать стратегию генерации SEQUENCE, так же как это описано в статье. Это будет работать без проблем. Одно лишь только «но», Hibernate в таком случае сам настроит генерацию индексов на стороне БД и настройка это будет не самой оптимальной.

Он создаст один общий индекс на всю вашу базу.

Представите что у вас 10 таблиц (сущностей) в базе, а тип индекса Integre, тогда в итоге у вас остается Integre.MAX_SIZE / 10 на каждую таблицу.

Избежать этого недостатка вам поможет аннотация @SequenceGenerator

SequenceGenerator

На этом пожалуй все, надеюсь что данная статья была вам полезна.

Сессии и DAO классы в Hibernate

Здравствуйте. Есть маленький проектик работающий с БД. В качестве ORM решения выбран Hibernate 4. Попутно обуздывая фреймворк, создал классы сущностей, связал аннотациями, использовал DAO pattern. Но: в имплементации ДАО классов в каждом изменяющем БД методе сессия открывалась и закрывалась прямо в методе (как и в этой туториал ссылочке http://javaxblog.ru/article/java-hibernate-1/). Пример

Session session = null; try < session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); // Здесь добавляю, обновляю или удаляю // . session.getTransaction().commit(); >catch (Exception e) < // Обрабатываю // rollback() >finally < // Закрываю if (session != null && session.isOpen()) < session.close(); >> 

Но что-то подсказывает, что это как-то, мягко говоря, не правильно.
Порыв немного интернет, наткнулся на статейку (https://developer.jboss.org/wiki/GenericDataAccessObjects), где говорится, что ДАО имплементации не должны создавать сессию внутри, а на неё нужно лишь ссылаться. Если я правильно понял, ДАО имплементаций не должно волновать создание сессий.

You could also use constructor injection. How you set the Session and what scope this Session has is of no concern to the actual DAO implementation. A DAO should not control transactions or the Session scope.

Интересует вопрос опытных разработчиков: создавать ли сессию один раз на всё приложение и просто в сеттере давать ссылочку ДАО классам (при этом сессию не закрывать), или же в каждом методе ДАО класса создавать и закрывать сессию?

Отслеживать
задан 29 ноя 2015 в 0:45
359 1 1 золотой знак 3 3 серебряных знака 16 16 бронзовых знаков
И да, может быть для доступа к сессии использовать синглтон?
Commented 29 ноя 2015 в 0:45
Синглтон не следует использовать вообще нигде, это антипаттерн.
Commented 29 ноя 2015 в 9:14

@pandal если операций слишком много. то вынести за пределы beginTransaction и commit. если мало, то можно и внутри заюзать.

Commented 13 мар 2018 в 14:36

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Жаль, что автор не нашёл время сам ответить на свой вопрос. Хоть я ни разу не опытный разработчик, попробую ответить на основании информации, которую нашёл в сети на текущий день.
На многих ресурсах рекомендуют использовать Hibernate в связке со Spring. Мне не нравится этот совет тем, что вводится лишняя «сущность». Человек учится пользоваться отвёрткой, а ему хотят всучить шуруповёрт. Да, вроде бы шуруповёрт круче, но и отвёрткой уметь пользоваться тоже не будет лишним.

Ручное открытие/закрытие сессии.
В первую очередь напрашивается такая структура взаимодействия: слой DAO содержит только основные (CRUD — create, read, update, delete) операции взаимодействия с базой данных; в бизнес-слой выносятся операции, которые можно (и нужно) объединять в транзакции.
Выглядит DAO-класс примерно так:

public class ItemDAOImpl implements ItemDAO < private Session session; public ItemDAOImpl(Session session) < this.session = session; >@Override public Item get(long id) < return session.get(Item.class, id, LockMode.PESSIMISTIC_READ); >@Override public long create(Item item) < return (Long) session.save(item); >@Override public void update(Item item) < session.update(item); >@Override public Item delete(long id) < Item item = session.byId(Item.class).load(id); session.delete(item); return item; >> 

Сессия session создаётся в бизнес-слое и передаётся в конструктор DAO:

public class AdminServiceImpl extends PersonServiceImpl implements AdminService < SessionFactory sessionFactory; public AdminServiceImpl(SessionFactory sessionFactory)< this.sessionFactory = sessionFactory; >@Override public long createItem(Item item) throws DBException < try (Session session = sessionFactory.openSession())< Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); long transaction.commit(); return id; >catch (HibernateException | NoResultException e) < throw new DBException(e); >> @Override public void updateItem(Item item) throws DBException < try (Session session = sessionFactory.openSession())< Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); dao.update(item); transaction.commit(); >catch (HibernateException | NoResultException e) < throw new DBException(e); >> @Override public void deleteItem(long id) throws DBException < try (Session session = sessionFactory.openSession())< Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); Item item = dao.delete(id); transaction.commit(); >catch (HibernateException | NoResultException | IllegalArgumentException e) < throw new DBException(e); >> > 

Недостаток метода очевиден — при большой нагрузке должен активно работать сборщик мусора, чтобы освобождать память от DAO- и сервисных объектов. Это осталось за кадром, но подразумевается, что также должен создаваться объект сервисного класса AdminServiceImpl . В конструкторе этот объект получает ссылку на объект типа SessionFactory .

Стратегия открытия сессии
Чтобы избавиться от постоянного создания dao — и сервисных объектов, нужен механизм создания сессии или получения текущей сессии в каждом из этих объектов независимо друг от друга. И тут на помощь приходят стратегии открытия-закрытия сессии. Рекомендую эту статью к прочтению. Допустим, что выбираем стратегию ManagedSessionContext — каждому потоку по отдельной сессии. Тогда для получения сессии можно будет использовать
Session session = sessionFactory.getCurrentSession();

Увы, сразу это не заработает. Чтобы заработало, нужно в hibernate.cfg.xml прописать thread .
Или второй способ — в конфигурацию hibernate добавить свойство
configuration.setProperty(«hibernate.current_session_context_class», «thread»);

Уже знакомый DAO-класс будет теперь выглядеть так:

public class ItemDAOImpl implements ItemDAO < ItemDAOImpl() < >@Override public Item get(long id) < return DBService.getSessionFactory() .getCurrentSession() .get(Item.class, id, LockMode.PESSIMISTIC_READ); >@Override public long create(Item item) < return (Long) DBService.getSessionFactory() .getCurrentSession() .save(item); >@Override public void update(Item item) < DBService.getSessionFactory().getCurrentSession() .update(item); >@Override public Item delete(long id) < Session session = DBService.getSessionFactory().getCurrentSession(); Item item = session.byId(Item.class).load(id); session.delete(item); return item; >> 

Здесь DBService — абстрактный класс, содержащий ссылку на объект SessionFactory . Так выглядит функция getSessionFactory() :

public static SessionFactory getSessionFactory()

А вот и переделанный сервисный класс:

public class AdminServiceImpl extends PersonServiceImpl implements AdminService < AdminServiceImpl() < >@Override public long createItem(Item item) throws DBException < Transaction transaction = DBService.getTransaction(); try < ItemDAO dao = DaoFactory.getItemDAO(); long transaction.commit(); return id; >catch (HibernateException | NoResultException e) < DBService.transactionRollback(transaction); throw new DBException(e); >> @Override public void updateItem(Item item) throws DBException < Transaction transaction = DBService.getTransaction(); try < ItemDAO dao = DaoFactory.getItemDAO(); dao.update(item); transaction.commit(); >catch (HibernateException | NoResultException e) < DBService.transactionRollback(transaction); throw new DBException(e); >> @Override public void deleteItem(long id) throws DBException < Transaction transaction = DBService.getTransaction(); try < ItemDAO dao = DaoFactory.getItemDAO(); Item item = dao.delete(id); transaction.commit(); >catch (HibernateException | NoResultException | IllegalArgumentException | IllegalStateException e) < DBService.transactionRollback(transaction); throw new DBException(e); >> > 

Вот используемые функции из DBService:

public static Transaction getTransaction() < Session session = DBService.getSessionFactory().getCurrentSession(); Transaction transaction = DBService.getSessionFactory().getCurrentSession().getTransaction(); if (!transaction.isActive()) < transaction = session.beginTransaction(); >return transaction; > public static void transactionRollback(Transaction transaction) < if (transaction.getStatus() == TransactionStatus.ACTIVE || transaction.getStatus() == TransactionStatus.MARKED_ROLLBACK) < transaction.rollback(); >> 

А вот класс DaoFactory для получения инстанса ItemDAO :

public abstract class DaoFactory < private static ItemDAO itemDAO = new ItemDAOImpl(); public static ItemDAO getItemDAO() < return itemDAO; >> 

Собственно, на этом, думаю, всё. Для тех, кто хочет пощупать код, вот ссылки на github:
— ручное управление сессией;
— управление при помощи ManagedSessionContext .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *