2014-02-17 4 views
3

У меня есть приложение spring/springwebflow (приложение A), которое использует кеш второго уровня Hibernate, а также кеш запросов. Приложение читает только из базы данных, а не добавлять/обновлять/удалять заявления.Hibernate Cache Атрибут области аннотации не работает

Запросы кэшируются в один регион под названием daoCache. Я поставил это аннотацией на namedQuerys

У меня есть объект с аннотацией из спящего режима @Cache с набором атрибутов для области «daoCache» слишком

@Entity 
@Table(name = "GROUP_OPERATOR") 
@SequenceGenerator(name = "SEQ_GROUP_OPERATOR", sequenceName = "SEQ_GROUP_OPERATOR") 
@NamedQueries({ 
@NamedQuery(name = "findGroupOperatorByMaster", query = "FROM GroupOperator groupOperator WHERE groupOperator.segment IS NULL and groupOperator.pointsMaster.pointMaster like ?", 
    hints={@QueryHint(name="org.hibernate.cacheRegion", value="daoCache"), 
     @QueryHint(name="org.hibernate.cacheable", value="true")}) 
}) 
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY, region = "daoCache") 
public class GroupOperator implements Serializable{ 
.... 

Кроме этого у меня есть другое приложение (приложение B), который подключается к одной базе данных и выполняет добавление/обновление/удаление по одной и той же базе данных.

По этой причине мы установили лимит в 20 минут, чтобы обновить область кеша в приложении A. Таким образом, изменения, внесенные в приложение B, отражается в приложении A через 20 минут.

Итак, предположим, что приложение A выполняет запрос «select * from group_operator, где point_master = 1000». Этот запрос будет сохранен в кеше с идентификатором результата, скажем, groupOperator # 1. Поэтому любое другое время (между 20 минутами), которое выполняет этот запрос, вернет из кеша идентификатор №1. И объект также будет сохранен в той же области кеша.

Проблема заключается в том, когда приложение B удаляет запись и создать новую (с другим ID) но * с теми же значениями, используемыми в качестве параметров в запросе *

Таким образом, между Через 20 минут приложение A вернет сущность groupOperator # 1, и в журнале приложений не отображаются инструкции выбора. Это ожидаемое поведение.

Через 20 минут кэш будет сброшен.

Теперь приложение пытается выполнить этот же запрос («выберите * из group_operator, где point_master = 1000»). Он выполнит запрос по базе данных, потому что кэширование было очищено через 20 минут. Таким образом, результатом должен быть новый идентификатор, созданный в приложении B. Но вместо этого я получаю ObjectNotFoundException. Нет строки с указанным идентификатором: groupOperator # 1

Даже операторы select отображаются в журнале, но все же возвращая старый идентификатор объекта. И, конечно, ID 1 больше не находится в базе данных.

Это очень странно, потому что я думал, что очистка кэша будет выполнять запрос снова

Если оба сущности и запрос кэшируются в том же регионе, почему до сих пор ищет старый объект?

Через несколько дней, исследуя это, используя кучи кучи, я обнаружил, что объект не кэшируется на «daoCache», указанном в аннотации @Cache. Но кэшируется в новом регионе с именем «xxx.xxx.xxx.xx.groupOperator». Кажется, что атрибут для этой аннотации не работает.

У меня есть несколько вопросов

1-Почему атрибут область в аннотации кэша не работает? Даже я установил «daoCache» - это beign, сохраненный в другом? это ошибка из спящего режима?

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

Это моя текущая конфигурация ehcache.xml

<cache name="daoCache" maxElementsInMemory="30000" eternal="false" 
     timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"> 
    </cache> 

    <cache name="rwCache" maxElementsInMemory="30000" eternal="false" 
     timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"> 
    </cache> 

    <cache name="xxx.xxxx.xxx.xxxx.groupOperator" maxElementsInMemory="30000"  eternal="false" 
     timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"> 
    </cache> 

Это мой провайдер кэш

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 

Используя следующую версию зимуют

<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-ehcache</artifactId> 
    <version>3.3.2.GA</version> 
</dependency> 


<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-core</artifactId> 
    <version>3.3.2.GA</version> 
</dependency> 

<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-commons-annotations 
    </artifactId> 
    <version>3.2.0.Final</version> 
</dependency> 

Спасибо за ваше время

UPDATE:

Я не уточнил, какой-либо hibernate.cache.region.factory_class. Поэтому я предполагаю, что используется по умолчанию. Не знаю, какой из них по умолчанию

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

проблемы является: ...

После удаления всех записей в таблице и проверке того, что кэш запросов работает Я добавил новую запись в одной таблице с теми же значениями, как и раньше, но разные первичные ID

После очистки кеша (автоматически через 20 минут) запрос выполняется снова по базе данных (это нормально, и я могу видеть, что операторы select в журнале). Найдена новая запись в таблице, и она должна вернуть идентификатор, чтобы затем загрузить весь Entity в память. Странно то, что когда он пытается получить всю Entity в память, он ищет этот объект, используя старый идентификатор, а не новый, который я добавил ранее. Это похоже на то, что запрос, даже выполненный снова по базе данных, все еще возвращает старый идентификатор. Но я повторяю, что кеш запросов работает нормально в других сценариях, и это точно.

Итак, я не понимаю, как кеш запросов и сущность объекта работают вместе. Это как проблема между кешем запроса и кэшем сущности. Я говорю это, потому что я решил это, добавив в ehcache.xml конфигурацию региона для этого Entity.

<cache 
    name="com.citi.latam.business.services.dao.model.db.campaign.groupOperator" 
    maxElementsInMemory="30000" eternal="false" timeToIdleSeconds="120" 
    timeToLiveSeconds="120" overflowToDisk="true"> 
</cache> 

ответ

0

Какие hibernate.cache.region.factory_class вы используете, EhCacheRegionFactory или SingletonEhCacheRegionFactory? Это может относиться к точке 1.

Для пункта 2 это работает, как вы упомянули, но запросы должны быть отмечены как кешируемые отдельно. В критерии API это делается с помощью setCacheable(true) и в JPQL с подсказкой запроса.

В связи с тем, что два тайника не синхронизированы, кеш запросов не обязательно вытесняется одновременно с областью кеша, в которой находится объект.

Запросы по умолчанию кэшируются в области кеша по умолчанию, но его можно выбрать регион, в котором запрос кэшируется с помощью API criteria.setCacheRegion().

Поместив соответствующий запрос в том же регионе кеша, что и объект, это обеспечит одновременное выдвоение как кэшированных запросов, так и кэшированных объектов.

+0

Я ответил вам с обновлением в своем вопросе. Взгляни, пожалуйста. Спасибо – user3320292

+0

Я отредактировал ответ для выталкивания кешей одновременно, но для выбора удара по базе данных и по-прежнему возвращаю древние значения, которые возможны только в том случае, если транзакция удаления/вставки не была выполнена, или если уровень изоляции REPEATABLE_READ/SERIALIZABLE хранится в течение огромного количества времени (20 минут) службой, выполняющей периодический запрос –

+0

Спасибо! Фактически я делаю транзакцию удаления вне основного приложения (из приложения B). Поэтому основное приложение не знает об изменениях, внесенных в приложение B. Это сценарий: приложение A читает, приложение B удаляет запись, приложение B создает новую запись с теми же значениями, что и удаленный, но другой идентификатор, приложение A снова читает , NotEntityFoundException выбрано. Я предполагаю, что сеанс hibernate в приложении A не знает об изменении таблицы, поэтому hibernate полагает, что изменений вообще не было и все еще ищет древний идентификатор. Возможно, это что-то связано с UpdateTimestampsCache, будет выглядеть – user3320292

2

FIXED!

Я, наконец, решил. Во-первых, то, что я сделал для того, чтобы все отладить из спящего режима и Ehcache

Поиск в журналах я нашел не правильной настройки моей базы данных модели

Объект GroupOperator имеет свойство Calendar. Проблема заключалась в том, что в календаре объектов также есть List of GroupOperator с аннотацией Cache. Поэтому каждый раз, когда Hibernate получает новый GroupOperator, также хотят обновлять дочерние сущности, такие как Календарь, но календарь имеет свой собственный список GroupOperator и кажется, что дочерние сущности не находятся в одном регионе кеширования или работают по-другому.

Проблема решена! Спасибо за ваше время @jhadesdev, было полезно продолжать расследование этого.

С уважением,