JPA默认会缓存实体吗?

21

我向数据库添加实体,它能正常工作。但是当我检索列表时,我获取到的是旧实体,直到我卸载应用程序并重新部署才会显示我添加的新实体。这意味着我的实体默认被缓存了吗?但是,我没有在persistence.xml或任何其他文件中设置缓存实体。

我甚至尝试调用flush()、refresh()和merge(),但仍然只显示旧实体。我是否遗漏了什么?请帮助我。

5个回答

22

欢迎使用JPA。如果您在JPA之外更新数据库,除非您知道自己在做什么并非常小心,否则您将会遇到很大的问题。这意味着您必须找出如何刷新缓存实体以便它们可以重新加载。

基本上,如果可能的话,请不要在JPA之外更新实体;如果您确实需要这样做,则很可能需要了解您特定的JPA提供程序使用的缓存模型的工作原理。如果您需要经常在JPA之外进行更新,那么JPA可能不是适合您的最佳选择。


1
但我没有在JPA之外更新数据库。我使用了JPA的persist方法,记录在数据库中可见。但是当我检索列表时,我看不到新添加的实体。请帮帮我。 - TCM
@Nitesh,你在使用事务吗?如果是的话,你有提交它们吗? - cletus
2
我没有使用entitymanager.getTransaaction或任何容器管理的事务。我可以在数据库中看到记录,但在检索的列表中却看不到。基本上,情况是这样的,假设有员工和部门表。部门表有员工集合。因此,如果我持久化员工记录,则可以在数据库中看到该记录,但在部门员工集合中却看不到,除非我显式地将其添加到员工集合中。这是必要的步骤吗?如果我有10个与一个实体相关的表。我是否必须将其添加到所有10个表的集合中?那太繁琐了吧? - TCM
1
@Nitesh 噢,不同的问题。是的,您绝对必须通过将Java对象放入该集合中来管理它。 - cletus
2
@Nitesh,情况正好相反:您更新对象,数据库会更新以反映这一点。您必须考虑是否希望您的一对多关系是单向还是双向的。仅因为您可以在一侧拥有实体集合并不意味着您应该这样做。 - cletus
显示剩余3条评论

14

这意味着我的实体默认会被缓存吗?

JPA 1.0并没有定义L2缓存(“共享缓存”),JPA 1.0只定义了一个L1缓存(“事务缓存”),但是JPA提供程序可以支持共享对象缓存,并且大多数提供程序都支持。如TopLink Essentials就支持通过JPA扩展来实现L1和L2缓存(每个JVM)。

现在,正如在这篇很好的文章Understanding the cache of TopLink Essentials(GlassFish JPA)中所解释的:

  • 来自同一持久性单元的所有EntityManager共享会话缓存(这就是TopLink称为第二级缓存的方式)。
  • 默认情况下打开会话缓存。
  • 如果在持久上下文中修改/删除实体,则在提交事务后将其同步到会话缓存,因此会话缓存的状态会更新(否则此类缓存根本无法使用)。

因此,您的设置肯定还有其他问题。您可以尝试通过添加以下属性来禁用共享会话缓存(仅限于测试目的):

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

但我会感到惊讶,如果这改变了什么的话。正如我所说,我认为还有其他问题。

PS:这并没有回答问题,但是,如果您正在使用GlassFish v3,为什么不使用EclipseLink?

更新:回答OP的评论

那么,如果我持久化雇员记录,则可以在数据库中看到它,但在部门的雇员集合中却无法看到它,直到我明确将其添加到雇员集合中。这一步是必需的吗?

嗯,如果您在Java层面上不创建实体之间的链接,JPA就无法在数据库中创建该链接(JPA只能执行您告诉它要执行的操作)。因此,是的,您需要创建链接,并且在双向关联的情况下,甚至需要设置链接的两个方面(例如将employee添加到Department的雇员集合中并设置Employeedepartment)。


3
嗨,Pascal Thivent。我在我的 persistence.xml 中提供了 EclipseLink,一切都运行得很好。但我仍然有另一个疑问,我也问了 cletus:基本上,情况是这样的:假设有员工和部门表。部门表具有员工集合。因此,如果我持久化员工记录,则它会出现在数据库中,但在部门员工集合中却看不到,除非我将其明确添加到员工集合中。这是必要的步骤吗?如果我有 10 张与一个实体相关的表,我是否必须将其添加到所有 10 个表的集合中?那太繁琐了吧? - TCM

2
JPA 2.0定义了共享(L2)缓存,但没有指定默认值。EclipseLink默认启用缓存,其他提供者则不启用。
EntityManager将始终具有持久性上下文(L1)缓存,直到调用clear()或创建新缓存为止。
您可以禁用共享缓存,
请参见:http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching 但您的问题在于未维护关系的双方。当您设置1-1时,需要添加到1-m,否则对象无效。
有关缓存的更多信息,请参见: http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching

0

我正在使用 eclipselinkejb 的上下文,我发现在查询实体时,它会自动被缓存,但是我也运行了一个函数来更改数据库中的记录,所以我可能会得到缓存中的旧数据,因此我通过向文件 persistence.xml 添加以下内容来禁用缓存:

<shared-cache-mode>NONE</shared-cache-mode>

它确实有效!


0

您是否正在使用EntityManager?如果没有,请尝试一下http://docs.oracle.com/javaee/5/api/javax/persistence/EntityManager.html

您是否在使用数据源来管理与数据库的连接?您也应该尝试使用它。这是在您的服务器中配置的XML文件。提供更多关于您的架构的信息,以便我们可以为您提供帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接