【问题标题】:Hibernate/JPA refresh whole collectionHibernate/JPA 刷新整个集合
【发布时间】:2018-03-07 02:38:17
【问题描述】:

我有一个Lazy load @OneToMany

@JsonIgnore
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private List<OrderItem> orderItems = new ArrayList<>();

经过长时间的操作,我想刷新orderItems实体。

我必须遍历孩子并刷新如下:

for (OrderItem orderItem : order.getOrderItems()) {
   entityManager.refresh(orderItem);
}

我认为这是非常不高效的,因为它正在尝试一个一个地刷新实体,这意味着它会一个一个地触发 SQL。

我相信当我们调用代理包装器getOrderItems 时,休眠是如何工作的,它只是触发一个 SQL 来通过父外键选择记录。这样更有效率。

我可以这样刷新整个列表吗?

【问题讨论】:

  • 能否解释一下为什么需要刷新实体?为什么不刷新父实体,或者完全取消交易?您所指的长操作是否包含在事务中?
  • @crizzis 刷新父实体会刷新子实体吗?我检查了级联类型,没有这样的选项。是的,长操作意味着它被包装在一个事务中。
  • ALL = DETACH, MERGE, PERSIST, REFRESH, REMOVE
  • @crizzis 我明白了.. 这是我的错误...我从这里忽略了它docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/…
  • @crizzis 所以通过刷新父级,休眠应该立即刷新集合对吗?而不是一一刷新子实体。

标签: java hibernate jpa jpa-2.0


【解决方案1】:

如果您不使用二级缓存,请使用命名查询来获取父实体和子关系。与逐个刷新每个成员相比,这将显着提高效率。

很酷的是,命名查询将绕过一级缓存。

如果你使用二级缓存,你需要先驱逐实体。

【讨论】:

    【解决方案2】:

    我怀疑是否有可能告诉 entityManager 用一条语句或一条 SQL 刷新整个集合。我认为如果 JPA 提供这样的功能并通过基于父 ID 发出单个 SQL 来进行刷新,那将非常好。

    EntitiManager.refresh() 方法期望我们传递一个托管实体。所以我们不能直接将 List 传递给这个方法。所以我看到的只有其他两个选项:

    1. 迭代集合并在每个实体上调用刷新。(如您所做的那样) 或
    2. 在子集合上使用 CascadeType.REFRESH 在父对象上调用刷新。尽管这仍会导致为子集合中的每个实体触发数据库查询。

    【讨论】:

    • 调用refresh 将导致放弃对列表中实体所做的更改。 merge 将导致完全相反的结果。在上述情况下,应该非常小心副作用
    • @crizzis 我的错误,我的意思是在父实体上调用刷新,而不是合并。更新。谢谢。
    猜你喜欢
    • 2013-02-11
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    • 2016-12-21
    • 1970-01-01
    相关资源
    最近更新 更多