在JPA中禁用缓存(eclipselink)

Jam*_*mes 44 java entity jpa eclipselink

我想使用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);
Run Code Online (Sandbox Code Playgroud)

一个==两个是真的,而我希望它是假的.

我尝试将以下每个/所有内容添加到我的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"/>
Run Code Online (Sandbox Code Playgroud)

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

@Cache(
  type=CacheType.NONE, // Cache nothing
  expiry=0,
  alwaysRefresh=true
)
Run Code Online (Sandbox Code Playgroud)

我误会了什么吗?

Jus*_*tin 39

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

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

另外,如果您希望使用JPA更新此数据,则需要在实体上获取悲观锁,以便底层数据不会在数据库中更改.

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

在你的代码中:

em.createNamedQuery("MyLocation.findMyLoc").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache).getResultList().get(0);
Run Code Online (Sandbox Code Playgroud)

或者在persistence.xml中:

<property name="eclipselink.query-results-cache" value="false"/>
Run Code Online (Sandbox Code Playgroud)


小智 26

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();
Run Code Online (Sandbox Code Playgroud)

这适合我.


小智 12

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

@Cacheable(false)
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

@Entity
@Table(name="SomeEntity")
@Cacheable(false)
public class SomeEntity {
    // ...
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 10

看到,

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

对于相同的EntityManager,JPA总是要求一个==两个,所以这是正确的,无论您的缓存选项(这是L1缓存,还是事务缓存,它强制执行事务隔离并维护对象标识).

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

<property name="eclipselink.cache.shared.default" value="false"/>
Run Code Online (Sandbox Code Playgroud)

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

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


Ali*_*330 5

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

em.createNamedQuery("findAll").setHint(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS).getResultList();
Run Code Online (Sandbox Code Playgroud)

效果非常好。我们可以看到 BYPASS 枚举的 javadoc 中是这样写的:

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

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


小智 5

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

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

entityManager.clear()
Run Code Online (Sandbox Code Playgroud)

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

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

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
Run Code Online (Sandbox Code Playgroud)