Почему мой Hibernate Query возвращает устаревшие данные? - PullRequest
4 голосов
/ 19 мая 2011

Быстрая версия

По сути, я обновляю таблицу Hibernate, а последующие запросы загружают устаревшее значение.

Подробная версия

Hibernate (3.3.1.GA) и EhCache (2.4.2).

Постоянный Book объект с List<PageContent> страницами, и я добавляю страницу в серединуэта книга.Я использую Databinder / Wicket, хотя я не думаю, что это связано.

 public void createPageContent(Book book, int index) {
     Databinder.getHibernateSession().lock(book, LockMode.UPGRADE);
     PageContent page = new PageContent(book);
     book.addPage(page, index);
     CwmService.get().flushChanges(); // commits the transaction
 }

Применимые поля / метод в Book:

@OneToMany
@JoinColumn(name="book_id")
@IndexColumn(name="pageNum")
@Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
private List<PageContent> pages = new ArrayList<PageContent>();

public synchronized void addPage(PageContent page, int index) {
    pages.add(index, page);
}

Конечный результатчто в список добавлена ​​новая страница, и база данных обновлена ​​соответствующим образом, и я подтвердил это в своем хранилище данных.Однако следующий запрос для страницы, скажем «Страница № 4», загружает «старую» Страницу № 4 вместо новой Страницы № 4:

criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);  

Итак, я неохотно удаляю кэширование из критериев,Он запрашивает хранилище данных, но по-прежнему возвращает неправильное значение .Однако в обоих случаях, если я подожду около 2 минут, все работает как положено.Я предполагаю, что кэширование все еще вовлечено.И PageContent, и Book используют эту стратегию кэширования:

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

Признаюсь, я новичок в кэшировании и просто настроил этот файл в первый раз.Вот мой ehcache.xml:

<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false"/>

<!-- Hibernate's Cache for keeping 'lastUpdated' data on each table.  Should never expire. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache" eternal="true" />

<!-- Hibernate's Query Cache - should probably be limited -->
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="1000" />

ОБНОВЛЕНИЕ : удаление аннотаций @Cache в моих объектах хранилища данных устраняет проблему.Конечно, я хотел бы кэшировать эти объекты, потому что модификация страницы гораздо реже, чем доступ.

Итак, мысли?Есть еще несколько вопросов, связанных с удалением страниц.Все обновляет базу данных, как и ожидалось, но фактическое поведение шаткое.

Заранее спасибо!

ОБНОВЛЕНИЕ # 2 : С помощью отладки я могу подтвердить, что в хранилище данных естьправильная информация, и когда запрос выполняется, он возвращается к кэшу второго уровня, который содержит грязную информацию.Я полагаю, что я не могу изымать из кэша каждый раз, когда данные изменяются?

Ответы [ 2 ]

0 голосов
/ 25 мая 2011

Я обнаружил проблему, но она вводит кое-что еще.

По сути, при изменении поля Book объекта *1003* Hibernate делает три вещи:

  1. ИстекаетЗапись кэша TimeStamp для Book и PageContent
  2. Выполняет ли много запросов сброс поля pageNum для каждого PageContent объекта
  3. Удаляет объект Book со второго уровняКэш.

Это гарантирует, что последующие запросы будут искать новые объекты и т. Д. Однако:

  1. Hibernate не удаляет каждый перенумерованный объект PageContent из кэша второго уровня

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

Я предполагаю, что этопотому что Hibernate чувствует, что изменение pageNum - это не изменение данных, а изменение закулисного управления.Однако это данные, которые я хотел бы прочитать и отобразить.

Решение состоит в том, чтобы вручную обновлять каждую страницу после вставки / удаления.

0 голосов
/ 20 мая 2011

После CwmService.get().flushChanges(); // commits the transaction сделать явный коммит.flush() только сбрасывает изменения в базу данных, но не фиксирует их.Я не уверен насчет flushChanges().

...