Почему мой запрос Hibernate возвращает устаревшие данные?

StackOverflow https://stackoverflow.com/questions/6064083

Вопрос

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

По сути, я обновляю таблицу 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

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

В принципе, при изменении Book объекты List<PageContent> поле Hibernate делает три вещи:

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

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

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

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

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

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

Другие советы

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top