Hibernate кэш 2-го уровня ObjectNotFoundException с большим количеством одновременных транзакций - PullRequest
7 голосов
/ 24 июня 2010

У нас есть Java-приложение, которое использует MySQL, Hibernate (3.5.1-Final) и EHcache (1.2.3) для нашего кэша 2-го уровня.

Наш уровень изоляции hibernate.properties - изоляция с фиксацией чтения = 2

# 2-Read committed isolation 
hibernate.connection.isolation=2

При большом количестве одновременных транзакций мы видим проблему, при которой определенные коллекции (ассоциации БД) при загрузке генерируют исключение ObjectNotFoundException, и кажется, что кэш 2-го уровня возвращает старую копию этой коллекции.

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

Мы не видим эту проблему при загрузке одной транзакции или даже при умеренной загрузке транзакции (10-20 одновременных подключений).

Например, у нас есть сущность персонажа:

@Entity
@Table(name = "CHARACTERS")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Character extends AbstractCharacter implements Serializable {
...
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    @OneToMany(mappedBy = "character", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<CharacterItem> items;

Мы надлежащим образом поддерживаем граф объектов при удалении сущностей, удаляя их из коллекции, в которой они содержатся, и вызывая session.delete ().

    character.getItems().remove(characterItem);
    session.delete(characterItem); 

Мы попытались изменить элементы набора; CacheConcurrencyStrategy от:

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<CharacterItem> items;

К

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<CharacterItem> items;

Без удачи.

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

На данный момент мы можем видеть только 2 решения:

  1. Попытайтесь поймать ObjectNotFoundException и попытаться интеллектуально выселить коллекцию (хотя в исключении не хватает контекста)

  2. Используйте аннотацию @ NotFound (action = NotFoundAction.IGNORE) для коллекции элементов, которая будет игнорировать и не выбрасывать исключение ObjectNotFoundException (но у нас есть опасения относительно как это работает с кэшем 2-го уровня и убедитесь, что он смотрит на правильные данные).

Хотелось бы, чтобы был @NotFound (action = NotFoundAction.EVICT_2ND_LEVEL_CACHE_RELOAD), где он вытеснил бы этот объект из кэша и попытался бы перезагрузить коллекцию.

Мы также можем попытаться изменить FetchyType с LAZY на EAGER, но я хочу попытаться понять проблему и выбрать лучшее решение, которое обеспечит согласованность данных в наших транзакциях при высоком параллелизме.

1 Ответ

1 голос
/ 28 июня 2010

Может быть, вам стоит попробовать session.evict(characterItem) вместо session.delete?

...