使用JPA获取旧数据

时间:2011-10-28 19:00:35

标签: java jpa eclipselink

即使我禁用缓存,我也会使用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

开始 flush commit 方法只是绝望的行为!我知道这不是必需的。

我忘了说一些重要:我做的测试是在直接在数据库控制台上添加用户记录,然后尝试通过我的webapp查看,这是未显示新用户。这就是我提到的“旧数据”,它只显示“老用户”。

我已经尝试将其放在 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 个答案:

答案 0 :(得分:16)

已经发布了一些建议,例如确保共享缓存已关闭,以及管理反向引用以使缓存一致。这些是针对可能发生的特定情况,但是您没有提供足够的信息来说明实际情况。

另一个特定的,但似乎可能基于你的getEntityManager()用法,如果你重用EntityManager实例而不清除它。 EntityManager保存对所有托管实体的引用,因为EM需要在后续查询中返回相同的实例并查找调用以维护身份。

如果尚未执行此操作,则需要清除EntityManager或在某些点获取新的EntityManager以释放内存和托管实体。

答案 1 :(得分:3)

首先,不要使用,

@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()或创建一个新的。

答案 2 :(得分:1)

使用

<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)

答案 3 :(得分:1)

与缓存答案(我将不得不尝试)相反,您可能会遇到未更新引用实体的情况。

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

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

保存Child后,您需要更新对Parent的引用,以便Memory Model(缓存)与数据库匹配。这是相当令人沮丧的,但我处理这个问题的方法是仅从父级进行级联。

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);
}

如果你设置它将会级联 - 我所看到的是反向级联(子级合并导致级联到父级)并不可靠 - 源于我对该主题缺乏了解。

简而言之 - 如果您明确处理数据层中的合并,则问题就会消失。我不愿意禁用缓存,因为它可能会对大型应用程序产生重大影响,因此,我走了这条路。祝你好运,请告诉我们您的方法。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

EntityManager的使用是关键。几个月后,我已经达到了完美的解决方案:

  • 对实体的所有READS使用通用DEFAULT实体管理器。这意味着为每个实体创建一个单独的实体管理器。
  • 为每个实体的每次写入/更新/删除操作创建一个新的实体管理器。使用begin / commit进行该新实体的事务。操作完成后关闭实体管理器。
  • 节点:提交并关闭编写器实体管理器后,清除DEFAULT实体管理器(读取器1)。这意味着写完后才能清楚;不是每次阅读之前。