Срок службы кеша JPA / Eclipselink - PullRequest
4 голосов
/ 13 августа 2010

1.- Я работаю с Glassfish 2.1 с EcipseLink 2.0.0, поэтому действительно использую спецификацию JPA 1.0, и у меня есть EJB без состояния, который находит сущности среди прочего. Насколько я знаю, JPA 1.0 определяет кэш L1, который работает на уровне контекста постоянства (уровень транзакции для EJB без сохранения состояния), но я не могу понять, почему следующий код выводит «Not same instance», если он находится в той же транзакции.

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)    
public class EntityServiceBean implements EntityServiceLocal {
    @PersistenceContext(unitName = "Model")
    private EntityManager entityManager;
    @Override
    public <T> T find(Class<T> type, Object id) {
        T entity = entityManager.find(type, id);
        if(entity != entityManager.find(type, id)) {
            System.out.println("Not same instance");
        }
        return entity;
    }
    ....
}

Я даже пытался со свойством:

<property name="eclipselink.cache.type.default" value="Full"/>

в файле persistence.xml, но делает то же самое.

2.- Чего я действительно хотел бы достичь, если это возможно, так это того, чтобы множественные вызовы моего EJB без сохранения состояния возвращали один и тот же экземпляр, иными словами, охватывали бы жизнь кеша JPA между транзакциями и контекстами постоянства с использованием EJB без сохранения состояния, например:

... // POJO class
EntityServiceLocal entityService = ...
Product pA = entityService.find(Product.class, 1l);
...
Product pB = entityService.find(Product.class, 1l);
System.out.println("Same instance?" + pA == pB); // TRUE

Я читал, что во многих реализациях JPA используется кэш L2 (теперь определен в JPA 2.0), который охватывает несколько контекстов персистентности даже в JPA 1.0, но я не знаю, неправильно ли понял концепцию кэша L2 и / или я пропускаю любая конфигурация.

Возможно ли это? Или что я могу сделать, чтобы избежать чтения более 20 000 сущностей из БД каждую минуту, чтобы обновить те, которые в этом нуждаются?

Ответы [ 3 ]

4 голосов
/ 13 августа 2010

Я работаю с Glassfish 2.1 с EcipseLink 2.0.0, поэтому действительно использую спецификацию JPA 1.0, и у меня есть EJB без состояния, который находит сущности среди других вещей.Насколько я знаю, JPA 1.0 определяет кэш L1, который работает на уровне контекста постоянства (уровень транзакции для EJB без сохранения состояния), но я не могу понять, почему следующий код выводит «Not same instance», если он находится в той же транзакции.

ЭТО чрезвычайно странно, идентичность объекта обязательно должна поддерживаться внутри транзакции в контексте Java EE.Это очень хорошо задокументировано в JPA wiki book :

Идентичность объекта

Идентификация объекта в Java означает, что две переменные (x, y) ссылаются на тот же логический объект, тогда x == y возвращает true.Это означает, что оба ссылаются на одну и ту же вещь (оба указателя на одну и ту же ячейку памяти).

В JPA идентичность объекта поддерживается внутри транзакции и (обычно) внутри одного и того же EntityManager.Исключение составляет управляемый JEE EntityManager, идентификация объекта поддерживается только внутри транзакции.

Таким образом, в JPA верно следующее:

Employee employee1 = entityManager.find(Employee.class, 123);
Employee employee2 = entityManager.find(Employee.class, 123);
assert (employee1 == employee2);

Это верно независимо от того, как объектДоступ:

Employee employee1 = entityManager.find(Employee.class, 123);
Employee employee2 = employee1.getManagedEmployees().get(0).getManager();
assert (employee1 == employee2);

В JPA идентичность объекта не поддерживается в EntityManager.Каждый EntityManager поддерживает свой собственный контекст постоянства и свое собственное транзакционное состояние своих объектов.

Таким образом, в JPA верно следующее:

EntityManager entityManager1 = factory.createEntityManager();
EntityManager entityManager2 = factory.createEntityManager();
Employee employee1 = entityManager1.find(Employee.class, 123);
Employee employee2 = entityManager2.find(Employee.class, 123);
assert (employee1 != employee2);

Идентификация объекта обычно является хорошей вещью, так какИзбегает, чтобы ваше приложение управляло несколькими копиями объектов, и избегает изменения приложением одной копии, но не другой.Причина, по которой разные EntityManager или транзакции (в JEE) не поддерживают идентичность объекта, заключается в том, что каждая транзакция должна изолировать свои изменения от других пользователей системы.Как правило, это также хорошо, но требует, чтобы приложение знало о копиях, отсоединенных объектах и ​​слиянии.

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

И я не могу воспроизвести проблему с EclipseLink 2.0 в среде Java SE (внутри транзакции и того же EntityManager) - извините, я выиграл 't test под GF 2.1.

Я даже пробовал со свойством: <property name="eclipselink.cache.type.default" value="Full"/> в файле persistence.xml, но делает то же самое

Ничего не значит "Активировать »для кэша L1.

Чего я действительно хотел бы достичь, если это возможно, так это того, чтобы множественные вызовы моего EJB без сохранения состояния возвращали один и тот же экземпляр, другими словами, охватывали бы срок действия кэша JPA между транзакциямии контексты постоянства с использованием EJB без сохранения состояния (...):

Кэш L2 действительно является кешем, охватывающим несколько транзакций, а также EntityManager и L2 cacHing поддерживается большинством провайдеров JPA.Но хотя кэширование L2 уменьшит количество обращений к базе данных, идентичность объекта не гарантируется всеми провайдерами.

Например, в Hibernate кэш L2 не включен по умолчанию, и вы не получите идентификацию объекта, поскольку Hibernate не помещает сами объекты в кэш.

С EclipseLink по умолчанию включен L2 кеш , и вы получите идентификатор объекта в зависимости от типа кеша .По умолчанию используется кэш SOFT-WEAK размером 100 , и он сохраняет идентичность объекта.В то время как вы можете очень точно настраивать вещи (вплоть до уровня сущности), для распределенной среды или нет, все должно работать по умолчанию.

См. Также

1 голос
/ 02 ноября 2011

Какие другие настройки вы установили, и как вы наметили свой класс?

Две находки в одной и той же транзакции всегда должны быть одним и тем же экземпляром.

Вы можете заставить find () возвращать один и тот же экземпляр через границы транзакции, если вы пометите объект или сделаете запрос только для чтения (@ReadOnly, "eclipselink.read-only" = "true"). Вам нужно будет убедиться, что вы используете его только для чтения. Попытка разрешить обновления одного и того же экземпляра, совместно используемого различными транзакциями, невозможна и не является хорошей идеей.

0 голосов
/ 16 октября 2010

Мы обнаружили, что кэш сущностей Eclipselink L2, кажется, не выполняет то, что должен делать вообще. У нас относительно мало объектов для хранения в кеше L2 из базы данных, но наше использование памяти выходит из-под контроля в течение 24 часов, пока у нас не кончится куча (стоимостью 4 ГБ). Я профилировал приложение и подтвердил, что использование памяти происходит из L2-кэша Eclipselink. Мы используем SOFT-WEAK, и он никогда не удаляет старые объекты, насколько мы можем судить (то, что документы предполагают, что он должен делать), и создает несколько экземпляров объектов, свойства которых одинаковы (что документы предполагают, что это НЕ должен делать), это приложение только для чтения ради бога. Нам также совершенно не удалось заставить работать любой способ координации кэша в кластерной среде. У нас было три старших разработчика Java с более чем десятилетним опытом работы, каждый из которых фактически работал в IBM над их реализацией Java, но не смог добиться какой-либо координации кеша для работы, периодически тратя время на решение проблемы в течение последних шесть месяцев даже прослеживая источник Eclipselink, чтобы выяснить, что происходит не так. Перезагружать наше приложение каждые 24 часа становится довольно утомительно, и я уже почти закончил кеширование L2. Я только надеюсь, что мы сможем получить приемлемую производительность без нее, по крайней мере, реализациям Eclipselink JPA 1 удалось выполнить параллельное чтение, которое, похоже, испарилось в JPA 2. Разработчики баз данных решили эту проблему много лет назад с MVCC, почему набор интеллектуальных Разработчики Java не могут управлять тем же умением, учитывая, что оно уже сделано? Все, что мы делаем, - это, по сути, перемещаем его вверх по течению и выражаем данные в виде объектов вместо кортежей и страниц.

...