java 使用 JPA 获取旧数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7933617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:04:38  来源:igfitidea点击:

Getting old data with JPA

javajpaeclipselink

提问by André

I'm getting old data with JPA, even if I disable the cache. I guess is because the resource is configured to be RESOURCE_LOCAL, but I'm not sure.

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

My code that is getting old info about the user:

我的代码正在获取有关用户的旧信息:

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

My entity:

我的实体:

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

// some attributtes

}

Anybody has some idea of what is going on?

有人知道发生了什么吗?

UPDATE 1

更新 1

The begin, flushand commitmethods were just acts of desperation! I know it's not needed.

开始冲洗提交方法只是起到绝望!我知道它不需要。

I forgot to say something important: the test I make is to add a user record direct on database consoleand then try to see it through my webapp, which is not showing the new user. That is the "old data" I mentioned, it only displays "old users".

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

I already tried to put this on persistence.xmland I didn't see any difference in the results:

我已经尝试将它放在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"/>

So is something else…

还有别的东西……

回答by Chris

There are a few suggestions posted already such as ensuring the shared cache is off, and to manage back references so that the cache is consistent. These are for specific situations that could be occuring, but you have not provided enough to say what is really happening.

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

Another that is specific but seems possible based on your getEntityManager() usage, is if you are reusing the EntityManager instance without clearing it. The EntityManager holds a references to all managed entities since the EM is required to return the same instance on subsequent query and find calls to maintain identity.

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

If this is not done already, will want to clear the EntityManager or obtain a new one at certain points to release the memory and managed entities.

如果这还没有完成,将要清除 EntityManager 或在某些点获取新的 EntityManager 以释放内存和托管实体。

回答by James

First off, don't use,

首先,不要使用,

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

just set,

刚设置,

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

Second, where is your EntityManager coming from? Do you create a new one per request/transaction? If you don't then everything read in the EntityManager will be in its (L1) cache. You need to call clear() or create a new one.

其次,你的 EntityManager 来自哪里?您是否为每个请求/交易创建一个新的?如果不这样做,则 EntityManager 中读取的所有内容都将位于其 (L1) 缓存中。您需要调用 clear() 或创建一个新的。

回答by Matthias Bruns

Use

利用

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

or

或者

@Cache(shared=false)

回答by Daniel B. Chapman

As opposed to the caching answer (which I will have to try) you're likely running into a situation where your referenced entity isn't updated.

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

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

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

Upon saving the Child you need to update your reference to Parent so that the Memory Model (cache) matches the database. It is fairly frustrating, but the way I've dealt with this is to cascade only from the parent.

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

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

This will cascade if you set it up--what I've seen is that the reverse cascade (the child merge causes a cascade to the parent) has not been reliable--stemming from my lack of knowledge in the subject.

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

In short--if you handle the merge in your data-layer explicitly, the problem goes away. I'm reluctant to disable caching as it could have a significant impact in large applications, thus, I went this route. Good luck, and please let us know your approach.

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

回答by user992756

1) Refine the code

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)Remove @Cache (type=CacheType.NONE) from your entity class

2) 从你的实体类中移除 @Cache (type=CacheType.NONE)

3) No need to change persistence.xml

3)无需更改persistence.xml

回答by Ebru Yener

The usage of EntityManager is the key. I've reached the perfect solution after months:

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

  • Use a common DEFAULT entity manager for all READS of an entity. This means create a separate entity manager for each entity.
  • Create a new entity manager for each write/update/delete operation of each entity. Use begin/commit for transaction of that new entity. Close the entity manager after the operation finish.
  • The node point: Clear the DEFAULT entity manager (reader one) after you commit and close the writer entity manager. This means only clear after write; not before each read.
  • 对实体的所有 READS 使用通用的 DEFAULT 实体管理器。这意味着为每个实体创建一个单独的实体管理器。
  • 为每个实体的每个写入/更新/删除操作创建一个新的实体管理器。对新实体的事务使用开始/提交。操作完成后关闭实体管理器。
  • 节点点:提交并关闭写入器实体管理器后,清除DEFAULT实体管理器(读取器一)。这意味着只有在写入后才清除;不是在每次阅读之前。