Получение старых данных с помощью JPA - PullRequest
6 голосов
/ 28 октября 2011

Я получаю старые данные с помощью JPA, даже если я отключаю кеш.Я предполагаю, потому что ресурс настроен как RESOURCE_LOCAL, но я не уверен.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="AppPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.myentities.User</class>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/mydatabase"/>
            <property name="javax.persistence.jdbc.password" value="*****"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.user" value="user1"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>
</persistence>

Мой код, который получает старую информацию о пользователе:

public List<User> findAll(App app) {       
        getEntityManager().getTransaction().begin();        
        Query q = getEntityManager().createQuery("SELECT t1 FROM User t1 WHERE t1.app.idApp=:idApp");
        q.setParameter("idApp", app.getIdApp());
        getEntityManager().flush();
        getEntityManager().getTransaction().commit();
        List resultList = q.getResultList();        
        return resultList;
    }

Моя сущность:

@Entity
@Table(name = "user")
@Cache (
     type=CacheType.NONE
     )
public class User implements Serializable {

// some attributtes

}

У кого-нибудь есть представление о том, что происходит?

ОБНОВЛЕНИЕ 1

begin , flush и коммит методы были просто актами отчаяния!Я знаю, что это не нужно.

Я забыл сказать что-то важно : тест, который я делаю, это добавление записи пользователя непосредственно в консоль базы данных , а затем попытка увидетьэто через мое веб-приложение, которое не показывает нового пользователя .Это «старые данные», о которых я упоминал, они отображают только «старых пользователей».

Я уже пытался поместить их в persistence.xml , и я не увидел никакой разницы врезультаты:

<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.cache.size.default" value="0"/>
<property name="eclipselink.cache.type.default" value="None"/>

Так что-то еще ...

Ответы [ 6 ]

16 голосов
/ 29 октября 2011

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

Другая особенность, которая кажется возможной в зависимости от вашего использования getEntityManager (), - это если вы повторно используетеЭкземпляр EntityManager без его очистки.EntityManager содержит ссылки на все управляемые объекты, поскольку EM должен возвращать один и тот же экземпляр в последующем запросе и находить вызовы для поддержания идентичности.

Если это еще не сделано, он захочет очистить EntityManager или получитьновый в определенные моменты, чтобы освободить память и управляемые объекты.

3 голосов
/ 31 октября 2011

Во-первых, не используйте,

@Cache(type=CacheType.NONE)
or,
<property name="eclipselink.cache.size.default" value="0"/>
or,
<property name="eclipselink.cache.type.default" value="None"/>

просто установлено,

@Cache(shared=false)
or,
<property name="eclipselink.cache.shared.default" value="false"/>

Во-вторых, откуда ваш EntityManager? Вы создаете новый для каждого запроса / транзакции? Если вы этого не сделаете, все, что читается в EntityManager, будет находиться в его (L1) кэше Вам нужно вызвать clear () или создать новый.

1 голос
/ 28 октября 2011

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

@Entity
Class Parent
{
  @OneToOne(Cascade.ALL)//Or only Merge, whatever you're needs
  Child child;
}

@Entity
Class Child
{
  Parent parent;
  ... Values
}

После сохранения дочернего элемента вам необходимо обновить ссылку на родительский элемент, чтобы модель памяти (кэш) соответствовала базе данных. Это довольно неприятно, но я справился с этим только каскадно от родителя.

public void saveChild(Child child)
{
  child.getParent().setChild(this); //or DTO Code, whatever
  EntityManager.merge(parent); //cascades to the child.
  //If you're manually cascading (why?) 
  //EntityManager.merge(child);
}

Это будет каскад, если вы настроите его - я видел, что обратный каскад (дочернее слияние вызывает каскад для родителя) не был надежным - из-за моего недостатка знаний в предмете.

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

1 голос
/ 28 октября 2011

Используйте

<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.cache.size.default" value="0"/>
<property name="eclipselink.cache.type.default" value="None"/>

или

@Cache(shared=false)
0 голосов
/ 12 июня 2015

Использование EntityManager является ключевым.Через несколько месяцев я нашел идеальное решение:

  • Использование общего менеджера сущностей DEFAULT для всех ЧТений сущности.Это означает создание отдельного менеджера сущностей для каждой сущности.
  • Создание нового менеджера сущностей для каждой операции записи / обновления / удаления каждой сущности.Используйте начало / принятие для транзакции этой новой сущности.После завершения операции закройте диспетчер сущностей.
  • Точка узла: очистите диспетчер сущностей DEFAULT (считыватель один) после фиксации и закройте диспетчер сущностей пишущего устройства.Это означает только очистить после записи;не перед каждым прочтением.
0 голосов
/ 03 ноября 2011

1) Уточнить код

public List<User> findAll(App app) {   
    Query q = getEntityManager().createQuery("SELECT t1 FROM User t1 WHERE    t1.app.idApp=:idApp");    q.setParameter("idApp", app.getIdApp());                 
    List resultList = q.getResultList();            
    return resultList;    
} 

2) Удалите @Cache (type = CacheType.NONE) из вашего класса сущностей

3) Нет необходимости изменять persistence.xml

...