即使我禁用缓存,我也会使用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
}
有人知道发生了什么事吗?
开始, 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"/>
所以还有别的......
答案 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的使用是关键。几个月后,我已经达到了完美的解决方案: