51

我想使用 JPA (eclipselink) 从我的数据库中获取数据。数据库由许多其他来源更改,因此我想为我执行的每个查找返回数据库。我已经阅读了许多关于禁用缓存的帖子,但这似乎不起作用。有任何想法吗?

我正在尝试执行以下代码:

        EntityManagerFactory entityManagerFactory =  Persistence.createEntityManagerFactory("default");
        EntityManager em = entityManagerFactory.createEntityManager();

        MyLocation one = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);

        MyLocation two = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);    

        System.out.println(one==two);

one==two 是真的,而我希望它是假的。

我尝试将以下每个/所有内容添加到我的 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"/>

我还尝试将 @Cache 注释添加到实体本身:

@Cache(
  type=CacheType.NONE, // Cache nothing
  expiry=0,
  alwaysRefresh=true
)

我是不是误会了什么?

4

8 回答 8

44

这种行为是正确的,否则如果您使用不同的值更改对象一和对象二,则在持久化它们时会遇到问题。正在发生的是调用加载对象二更新了第一次调用中加载的实体。它们必须指向同一个对象,因为它们是同一个对象。这确保了脏数据不能被写入。

如果您在两次调用之间调用 em.clear(),实体一应该分离,您的检查将返回 false。但是没有必要这样做,eclipse链接实际上将您的数据更新到最新的我猜这是您想要的,因为它经常更改。

附带说明一下,如果您希望使用 JPA 更新此数据,则需要在实体上获得悲观锁,以便数据库中的基础数据无法更改。

您将需要禁用查询缓存以及您的缓存选项只是从播放中删除对象缓存而不是查询缓存,这就是您没有得到新结果的原因:

在您的代码中:

em.createNamedQuery("MyLocation.findMyLoc").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache).getResultList().get(0);

或者在 persistence.xml 中:

<property name="eclipselink.query-results-cache" value="false"/>
于 2010-05-11T09:26:56.130 回答
30
final Query readQuery = this.entityManager.createQuery(selectQuery);
readQuery.setParameter(paramA, valueA);

// Update the JPA session cache with objects that the query returns.
// Hence the entity objects in the returned collection always updated.
readQuery.setHint(QueryHints.REFRESH, HintValues.TRUE);

entityList = readQuery.getResultList();

这对我有用。

于 2012-12-04T18:44:45.460 回答
24

如果您希望在不获取特定供应商的情况下禁用缓存,您可以使用以下方式注释您的域对象:

@Cacheable(false)

这是一个例子:

@Entity
@Table(name="SomeEntity")
@Cacheable(false)
public class SomeEntity {
    // ...
}
于 2015-10-16T00:34:46.513 回答
13

看,

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching

对于同一个 EntityManager,JPA 总是要求 one==two,所以这是正确的,无论您的缓存选项如何(这是 L1 缓存或事务缓存,它强制您的事务隔离并维护对象身份)。

要强制刷新查询(并恢复您所做的任何更改),您可以使用查询提示“eclipselink.refresh”="true"。或者可能更好,为每个查询/请求使用一个新的 EntityManager,或者在你的 EntityManager 上调用 clear()。

<property name="eclipselink.cache.shared.default" value="false"/>

是禁用共享缓存(L2 缓存)的正确方法。请删除所有其他设置,因为它们不正确,可能会导致问题。

EclipseLink 默认不维护查询缓存,因此这些设置不会产生影响。CacheUsage 也不正确,不要使用它(它用于内存查询)。

于 2012-12-05T14:12:44.027 回答
5

一级缓存默认启用,您不能禁用它。即persistence.xml 文件中的任何设置都不会禁用一级缓存。

您只能通过调用清除所有实体管理器对象

entityManager.clear()

这将使后续查询(第一次)进入数据库,然后对象再次存储在缓存中

您可以通过调用强制每个查询直接进入数据库

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
于 2018-03-08T10:49:43.927 回答
4

如果手动修改对象的属性,例如 MyLocation。上面的技巧 ( CACHE_USAGE=CacheUsage.DoNotCheckCache, 或eclipselink.query-results-cache=false) 在我尝试时似乎不起作用。

所以我试图设置另一个提示,即eclipselink.refresh, to true。然后它工作。我的意思是手动更改的属性被检索。

据我了解,上述技巧只能确保它获得正确的对象。但是,如果对象已经被缓存,eclipselink 只会返回它们而不检查对象内容的新鲜度。只有当提示eclipselink.refresh设置为 时true,这些对象才会被刷新以反映最新的属性值。

于 2010-08-11T00:22:43.543 回答
4

我知道这篇文章可能已经过时了,但我正在为需要帮助的其他人写作。我遇到了这个问题,最后我通过以下代码解决了它:

em.createNamedQuery("findAll").setHint(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS).getResultList();

它真的很好用。我们可以在 BYPASS 枚举的 javadoc 中看到,它是这样写的:

绕过缓存:直接从数据库中获取数据。

请注意,我使用 Weblogic 12c 和 TopLink 作为 JPA 实现。

于 2016-08-23T14:21:02.223 回答
0

当您通过实体管理器创建查询时,将调用一级缓存。实体将是旧的。假设我有一个密钥,我在数据库中手动更新了它,然后尝试检索:

Key result = entityManager
                .createQuery("SELECT k FROM Key k WHERE k.linkKey = :key", Key.class)
                .setParameter("key", key)
                .getSingleResult();

以下键将保持原样,因为它仍然被缓存,我的更新不会出现。refresh对于实体,您需要调用它:

 entityManager.refresh(result);
于 2019-12-02T21:18:43.790 回答