【问题标题】:JPA @OneToMany by default is not so Lazy and fetch everything默认情况下,JPA @OneToMany 并不那么懒惰并获取所有内容
【发布时间】:2013-12-22 16:46:35
【问题描述】:

当前项目在 Spring + Openjpa + Roo 上运行。我有这样的实体

public class Zoo{
    ....
    @OneToMany(mappedBy="zoo", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private List<Elephant> elephants;

    @OneToMany(mappedBy="zoo", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private List<Jaguar> jaguars;

    @OneToMany(mappedBy="zoo", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private List<Tiger> tigers;
    ....
}

然后我有一个简单的 UI 页面,只是试图更新 Zoo 名称,但是在简单查询之后来自 SQL 跟踪日志

SELECT t0.id, t0.name 
FROM Zoo t0 
WHERE t0.id = ? 

有这样的查询

SELECT * FROM Zoo, Tiger, TigerProduct, TigerFood, FoodSupplier, SupplierContacts...

还有数百个这样的查询:

SELECT * FROM TigerProduct where tiger.id =: id_1
.....
SELECT * FROM TigerProduct where tiger.id =: id_n
....
....
SELECT * FROM TigerFood where tiger.id =: id_1
....
SELECT * FROM TigerFood where tiger.id =: id_n

Jaguar 和 Elephant 也是如此。当数据库中有大量数据时,这使得这个简单的操作变得非常慢。

第一个查询和后面的查询的 java 代码非常简单:

public static Zoo findZoo(Long id) {
    if (id == null) return null;
    return entityManager().find(Zoo.class, id);
}

从上面看,@OneToMany 关系上的默认 FetchType.Lazy 一点也不懒惰,以至于 JPA 试图提取链上的所有数据。

那么发生了什么以及如何清除这种情况?我只喜欢第一个查询,就是这样

【问题讨论】:

  • 我不明白:entityManager().find(Zoo.class, id) 是否也运行所有这些查询?您是否尝试过明确指定FetchType.LAZY(认为没有帮助)?您是否尝试过降级/升级 OpenJPA(因为在我看来,该实现中存在性能问题)?
  • @Andrei 我是的,在 java 代码中我确实指定了 FetchType.LAZY,但它并没有像您预期的那样帮助。你也是正确的,没有人对 UI 上的简单请求等一分钟返回结果感到满意。我们的 openjpa 已经是最新的了……但我在任何地方都找不到任何关于这种行为的线程或文章,让我觉得我的应用程序有错误,但 OpenJPA 没有。
  • 所以当你调用em.find() 时你会得到同样的行为?您是否尝试过降级 OpenJPA?
  • 发布你的 persistence.xml 的内容。

标签: spring jakarta-ee jpa ejb openjpa


【解决方案1】:

FetchType.Lazy 只是一个提示,而不是要求,如文档所述。所以你不能依赖这种行为,你只能希望你的 JPA 提供者尊重你的提示。此外,JPA 不会强制将 JPQL 查询或实体管理器调用转换为 SQL 代码,因此我们有责任选择一个知道如何做得更好的 JPA 提供者+版本(因为我们定义了更好的意思)。这可能是一个鼓励 JPA 提供商之间竞争的决定。

【讨论】:

  • 这个答案背后的想法:这是 JPA 实现的问题(在这种情况下为 OpenJPA),因为 JPA 本身无法控制此类行为。
  • -1 因为您的回答无助于回答问题。您陈述的事实无助于深入了解操作人员正在观察的行为。这很可能是使用 OpenJPA 的问题,而不是实现错误。
  • 这不是downvote的目的。关于问题,用 JPA 查询替换 find 调用。
猜你喜欢
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
  • 2023-03-23
  • 2016-06-01
相关资源
最近更新 更多