【问题标题】:HowTo implement "update" in Hibernate JPA2如何在 Hibernate JPA 2 中实现“更新”
【发布时间】:2011-04-05 06:13:10
【问题描述】:

有人可以提供一个简单的例子来演示如何实现一个简单的“更新”方法吗?这个不更新了

@Override
public void update(final BS bs) {
    BS fullBs = em.find(BS.class, bs.getId());
    BS merged = this.em.merge(fullBs);
    this.em.flush();
}

谢谢

【问题讨论】:

  • 为什么你认为它应该有效?您只需找到一个实体,然后将其保存(合并)回来。没有任何变化。
  • 我不知道合并实际上做了什么。然而,用你的评论重新阅读我的台词,我意识到我的错误。

标签: hibernate orm jpa jpa-2.0


【解决方案1】:

有人可以提供一个简单的例子来演示如何实现一个简单的“更新”方法吗?这个不更新(...)

嗯,这实际上取决于您要更新的实体的状态(托管与分离),但您的代码绝对没用。我们来分析一下:

1. public void update(final BS bs) {
2.     BS fullBs = em.find(BS.class, bs.getId());
3.     BS merged = this.em.merge(fullBs);
4.     this.em.flush();
5. }
  1. 正如我所说,作为参数传递的bs 实体的状态尚不清楚。无论如何...
  2. 然后您使用其Id 将托管实体加载到fullBs 中,并且...您不要更改任何内容
  3. 然后您尝试 merge 一个完全没有必要的已托管实体(JPA 为托管实体提供 automatic state detection)。
  4. 而你 flush 所做的更改...不存在 :)

因此,正如您所试验的那样,您的方法目前没有做任何事情。

现在回到问题:

  • 如果你想更新一个托管实体,你不应该调用任何方法,JPA 会自动检测任何状态变化并在flush time 持久化这些变化
  • 如果你想更新一个分离的实体,你应该使用merge(并返回合并的实例)。

另见

参考文献

  • JPA 2.0 规范
    • 第 3.1.1 节“EntityManager 接口”
    • 第 3.2 节“实体实例的生命周期”
    • 第 3.2.7 节“分离的实体”
    • 第 3.2.8 节“托管实例”

【讨论】:

  • 非常感谢您的准确解释和参考列表,这对像我这样的 JPA 初学者非常有用。
【解决方案2】:

hibernate 中的更新是使用脏检查而不是显式更新调用来实现的。例如在上面的方法中,如果你find()你的BS实体然后修改一个属性然后调用flush()你会看到一个SQL更新正在生成。不修改 flush() 将决定无事可做。

例子

@Override
public void update(final BS bs) {
    BS fullBs = em.find(BS.class, bs.getId());
    fullBs.setMyProperty("hello");
    this.em.flush();
}

当您执行find() 时,实体由 JPA 提供程序(在这种情况下为休眠)加载,休眠将为您提供实体,并且它在加载时保留实体状态的内部记录加上它持有对它返回的实体的引用。

然后当flush() 被调用时,hibernate 会检查其缓存中的每个实体(称为一级缓存或会话缓存)。脏检查包括使用内部状态记录检查您获得的实体的每个属性。如果有任何差异,实体是“脏”的,将生成 SQL 更新。

请注意,flush() 不是事务提交。它只是说,“请立即将会话中所做的任何更改保存到数据库”,这将涉及插入/更新/删除语句。

merge() 不是简单更新所必需的。

此外,您通常不会显式调用flush()。通常最好让hibernate这样做。 Hibernate 会在需要时刷新会话,这通常是在事务提交上,因此提交会为您执行刷新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    相关资源
    最近更新 更多