【问题标题】:Jpa query pulling from cache instead of database?Jpa查询从缓存而不是数据库中提取?
【发布时间】:2010-12-23 08:49:10
【问题描述】:

我的 Hibernate 支持的 Jpa 查询返回不是最新的数据时遇到问题。我认为这是从缓存而不是数据库本身提取数据的问题。

例如,我将在一个页面上更改和持久化一个对象,然后返回到上一页,其中列出了数据库的行,它将显示对象在更改之前存在的样子。我可以在我的日志中看到我的 DAO 触发了我的查询,我可以进入数据库并查看更改已保留,但是当我转到下一页时,JPA 没有从数据库中提取最新数据。

我相信可能有某种会话缓存在起作用,因为当我在另一个网络浏览器中加载页面时,我不会看到更新的数据库视图。

我该如何解决这个问题?

编辑:我做了一些后续测试,包括登录我的控制器以确保我的 MVC 框架(Spring MVC)没有缓存任何东西。事实并非如此,即使在控制器级别上它也会看到过时的数据库信息。


这是我的 ORM 实体文件中的映射 sn-p;

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = true)
@Column(name = "ID", nullable = false)
private Integer id;
@Basic(optional = false)
@Column(name = "Name", nullable = false, length = 100)
private String name;
@Basic(optional = false)
@Column(name = "DayOffset", nullable = false)
private int dayOffset;
@Basic(optional = false)
@Column(name = "StartTime", nullable = false, length = 5)
private String startTime;
@Basic(optional = false)
@Column(name = "Enabled", nullable = false)
private boolean enabled;
@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false, nullable =
false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
@Column(name = "TouchedBy", length = 50)
private String touchedBy;
@JoinTable(name = "ReconciliationSearchRule",
joinColumns = {@JoinColumn(name = "ReconciliationId",
    referencedColumnName = "ID", nullable = false)},
inverseJoinColumns = {@JoinColumn(name = "SearchRuleId",
    referencedColumnName = "ID", nullable = false)})
@ManyToMany(fetch = FetchType.LAZY)
private Collection<SearchRule> searchRuleCollection;
@JoinColumn(name = "ServerId", referencedColumnName = "ID", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Server server;
@OneToMany(mappedBy = "reconciliation")
private Collection<Report> reportCollection;

【问题讨论】:

  • “我可以看到我的 DAO 触发了我的查询”是什么意思?您的意思是您看到 SQL 被发送到数据库吗?你怎么知道你一开始就正确地坚持了改变?
  • 你如何保存你的实体? EntityManager.persist() 或 .merge() ?

标签: java hibernate orm jpa persistence


【解决方案1】:

我知道发生了什么。我的 DAO 作为原型(也称为非单例)被注入,因此每次使用 DAO 都会创建支持 EntityManager。 EntityManager 外部的数据库更改不会被对该特定 EntityManager 的查询注册。

当然,将 DAO 设置为单例会导致我的应用程序的多线程部分出现其他问题,但那完全是另一个问题。

【讨论】:

    【解决方案2】:

    有几种方法可以解决这个问题:

    1. 在相关实体上使用@DataCache(timeout = 1000) 设置驱逐策略,并将其设置为适合您使用的对象类型的合理值。
    2. 在您的实体或班级上致电 evict(...)。具体实现细节取决于您使用的提供程序(例如 Hibernate)。

    【讨论】:

    • 对于 1,你能用@DataCache 更详细地解释一下吗?对于 2,哪个类有 evict 方法?谢谢。
    • Hibernate Session 有 evict(),不适合你 ;)
    • @DataCache 是您在未刷新的类上放置的注释(因为它已被缓存)。此注释将指示 JPA 以通过 timeout 参数指定的频率逐出(或清除)此类对象的缓存。
    • @rynmrtn,所以你把你的实体类放在 ORM 层。 @DataCache 的默认值是什么?我在哪里可以找到 java 文档?
    • @rynmrtn,@DataCache 是 Hibernate 注释吗?我的 IDE 不知道从哪里导入它,我也没有找到它的文档。如果是 Hibernate,我不能直接使用它,因为我正在尝试通过 JPA 工作。
    【解决方案3】:

    例如,我将在一个页面上更改和持久化一个对象,然后返回到上一页,该页面列出了数据库的行,并且它将显示更改之前存在的对象。

    二级缓存管理应该是透明的,你不必在任何更新后手动evict()一个实体,二级缓存会被休眠“自动”为目标表失效。

    所以,我的问题是:“回到上一页”是什么意思?您的意思是使用导航器的“返回”按钮吗?你重新加载页面了吗?你能澄清一下吗?

    另外,您可以发布您的映射文件或带注释的实体吗?

    【讨论】:

    • Pascal,通过返回,我单击了一个超链接,将我带到另一个页面。我会在周一上班的时候发布更多信息。
    猜你喜欢
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2019-07-28
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 2018-02-09
    • 1970-01-01
    相关资源
    最近更新 更多