默认情况下,JPA @OneToMany不是那么懒惰并且获取所有内容

时间:2013-12-05 16:19:48

标签: spring java-ee jpa ejb openjpa

当前项目在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

同样对于美洲虎和大象也是如此。当数据库中存在大量数据时,这使得这个简单的操作非常慢。

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

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

从上面看起来,FetchType.Lazy关系上的默认@OneToMany看起来并不是很懒,以至于JPA试图拉动链上的所有数据。

那是怎么回事以及如何清除这种情况?我只喜欢有第一个查询,就是它

1 个答案:

答案 0 :(得分:1)

正如文档所说,

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