Выложил на github проект Hibernate Dynamic SQL Cache.
Описание
Данный проект успешно используется мной в нескольких проектах и показал хорошую эффективность. Причиной для создания проекта послужил неэффективный механизм кэширования в Hibernate, впрочем сами разработчики открыто пишут об этом в документации.
- HQL-кэш, а также кэш коллекций entity-объектов будут сбрасываться при каждом обновлении данных в хотя бы в одной из таблиц, участвующих в запросе. При очень частых обновлениях таблиц польза от такого рода кэшей сводится к 0.
- SQL-кэш держит в памяти лишь результат первого вызова запроса и не сбрасывается.
Поэтому возникла идея создания динамически обновляемого кэша. Результат запроса обновляется при INSERT или DELETE объекта в базе. Для использования данного решения следует немного изменить подход к построению запросов, а также использованию различных коллекций внутри entity-объектов.
- Запрос должен возвращать только id объекта. По этому id вы можете легко загрузить объект из кэша. (Таким образом получается два обращения к кэшу, что всегда быстрее выполнения запросов к базе)
- Запрос должен быть только по неизменяемым полям объекта.
- Вместо использования коллекций в entity-объекте использовать соответствующий SQL-запрос c динамическим обновлением.
Cache provider может использоваться абсолютно любой (Infinispan, Hazelcast, EHCache ...)
Проект опубликован под Apache License 2.0
Пример использования
Для наглядности примера используется Spring, хотя сам проект не привязан к нему, можно использовать любой другой контейнер.
Конфигурация hibernate. Здесь важно отметить использование собственного hibernate.cache.query_cache_factory
через который и осуществляется вся логика управления обновлениями кэшей:
Регистрируем com.corundumstudio.hibernate.dsc.QueryCacheEntityListener
который будет отслеживать основные операции по всем entity.
Пример DAO-сервиса. com.corundumstudio.hibernate.dsc.CacheCallback
- callback через который будет обслуживать операции "insert" или "delete" на объекте (в данном примере SimpleEntity), чтобы результаты запроса были всегда "свежими".
Теперь при вызове SimpleEntityDao.getEntityByPhone
, первый раз будет произведено обращение к БД. Последующие вызовы метода будут возвращать значение из кэша, причем если объект SimpleEntity
с искомым значением phone
будет добавлен в базу он также появится и в результате данного запроса. И наоборот, если объект с таким значением phone
будет удален, то результат запроса будет возвращать null
Если результат запроса возвращает список объектов, то в этом случае, при удалении/создании объекта, в списке будет удаляться/добавляться его id
Комментариев нет:
Отправить комментарий