Hibernate HQL работает только с кешем сессии
У меня возникли проблемы с пониманием, где HQL
запрос получает информацию от. Мой проект использует разные потоки, и каждый поток читает / пишет в базу данных. Потоки не разделяют объекты Session, вместо этого я использую HibernateUtil
класс, который создает сессии для меня.
До недавнего времени я закрывал сессию только после записи, а не после чтения. Изменения в объектах сразу же будут видны в базе данных, но при чтении в других потоках (объект Session отличается от того, который использовался для записи), я получаю устаревшую информацию. Чтение и запись происходили всегда в разных потоках, что означает разные объекты сеанса и разные кэши сеанса.
Я всегда думал, что с помощью HQL
вместо Criteria
Я всегда нацеливался на базу данных (или кэш второго уровня), а не на кэш сеанса, но при отладке моего кода мне было ясно, что HQL ищет объект в кеше сеанса и извлекает старый устаревший объект.
Был ли я неправ, предполагая, что HQL
всегда нацелен на базу данных? Или хотя бы кеш второго уровня?
PS: я использую только один SessionFactory
объект.
1 ответ
В Hibernate есть разные концепции кеширования - кеши сущностей и кеш запросов. Кэширование сущностей - это то, что делает кеш сеанса (и кеш 2-го уровня, если он включен).
Предполагая, что кеширование запросов не включено (по умолчанию это не так), тогда ваш HQL был бы выполнен для базы данных. Это вернуло бы идентификаторы сущностей, которые соответствуют запросу. Если бы эти объекты уже были в кеше сеанса, то Hibernate вернул бы их, а не перестраивал их из базы данных. Если в вашем сеансе есть устаревшие копии (потому что другой сеанс обновил базу данных), то это ваша проблема.
Я бы посоветовал не использовать долгоживущие сеансы, в основном по этой причине. Вы должны ограничить продолжительность сеанса определенной единицей работы, которую вы пытаетесь выполнить, а затем закрыть ее. Это практически не сказывается на производительности (если вы используете пул соединений с базой данных). Кроме того, чтобы убедиться, что вы не получите устаревшие объекты, вы можете позвонить Session.clear()
, но вы можете столкнуться с неожиданными побочными эффектами производительности.