Java 在 JPA (eclipselink) 中禁用缓存

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2809275/
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-08-13 13:04:39  来源:igfitidea点击:

Disable caching in JPA (eclipselink)

javajpaentityeclipselink

提问by James

I want to use JPA (eclipselink) to get data from my database. The database is changed by a number of other sources and I therefore want to go back to the database for every find I execute. I have read a number of posts on disabling the cache but this does not seem to be working. Any ideas?

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

I am trying to execute the following code:

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

        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 is true while I want it to be false.

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

I have tried adding each/all the following to my persistence.xml

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

I have also tried adding the @Cache annotation to the Entity itself:

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

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

Am I misunderstanding something?

我误解了什么吗?

采纳答案by Justin

This behavior is correct, otherwise if you change object one and object two with different values you will have problems when persisting them. What is happening is the call to load object two updates the entity loaded in the first call. They must point to the same object since they ARE the same object. This ensures that dirty data cannot be written.

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

If you call em.clear() between the two calls, entity one should become detached your check will return false. There is however no need to do that, eclipse link is infact updating your data to the latest which I would guess is what you want since it frequently changes.

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

On a side note if you wish to update this data using JPA you will need to be obtaining pessimistic lockson the Entity so that the underlying data cannot change in the DB.

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

You will need to disable the query cache as well your cache options were just removing the object cache from play not the query cache, that is why you are not getting the new results:

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

In your code:

在您的代码中:

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

Or in persistence.xml:

或者在persistence.xml中:

<property name="eclipselink.query-results-cache" value="false"/>

回答by Robin

If manually modifying the attributes of the object, for example MyLocation. The above trick (CACHE_USAGE=CacheUsage.DoNotCheckCache, or eclipselink.query-results-cache=false) does not seem to work as I tried.

如果手动修改对象的属性,例如 MyLocation。上面的技巧 ( CACHE_USAGE=CacheUsage.DoNotCheckCache, or eclipselink.query-results-cache=false) 似乎并没有像我尝试的那样工作。

So i tried to set another hint which is eclipselink.refresh, to true. then it works. I mean the manually changed attributes get retrieved.

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

So as i understand, the above trick only ensure the it gets the correct objects. However, if the objects have been cached already, eclipselink just returns them without checking the freshness of the contents of the objects. Only when the hint eclipselink.refreshis set to true, will these objects get refreshed to reflect the latest attribute values.

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

回答by Binu S

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

This works for me.

这对我有用。

回答by James

See,

看,

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

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

For the same EntityManager JPA always requires that one==two, so this is correct, not matter your caching options (this is the L1 cache, or transactional cache, which enforces your transaction isolation and maintains object identity).

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

To force the query to refresh (and revert any changes you have made) you can use the query hint "eclipselink.refresh"="true". Or probably better, use a new EntityManager for each query/request, or call clear() on your EntityManager.

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

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

Is the correct way to disable the shared cache (L2 cache). Please remove all your other settings as they are not correct, and can cause issues.

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

EclipseLink does not maintain a query cache by default, so those settings will have no affect. CacheUsage is also not correct, do not use this (it is for in-memory querying).

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

回答by diadyne

If you wish to disable caching without getting vendor specific, you could annotate your domain object with:

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

@Cacheable(false)

Here is an example:

下面是一个例子:

@Entity
@Table(name="SomeEntity")
@Cacheable(false)
public class SomeEntity {
    // ...
}

回答by AliReza19330

I know this post might be old, but I am writing for others who need help. I had this problem and finally I solved it by this code:

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

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

It works really well. And we can see in javadoc of the BYPASS enum, it is written that:

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

Bypass the cache: get data directly from the database.

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

I should notice that I use Weblogic 12c and TopLink as a JPA implementation.

我应该注意到我使用 Weblogic 12c 和 TopLink 作为 JPA 实现。

回答by Michael

First level cache is enabled by default and you can not disable it. i.e. no settings in your persistence.xml file will disable first level cache.

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

You can only clear out all the entity manager objects by calling

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

entityManager.clear()

this will make subsequent queries go to the database (the first time) and then objects are again stored in the cache

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

You can force each query to go to the database directly by calling

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

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);

回答by Georgi Peev

When you create your query via the entity manager the first-level cache is called.The entity will be old. Lets say I have a key ,which I updated manually in the database and then tried to retrieve:

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

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

The following key will be as it was ,because it is still cached ,my update will not appear.To refreshthe entity you will need to call this:

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

 entityManager.refresh(result);