JPA对原始属性也懒惰吗?

时间:2017-05-03 01:52:27

标签: java hibernate jpa eclipselink

我正在尝试检测代码中的N + 1问题。我发现的每个问题的例子总是涉及两个实体,这并没有真正解释这是否也可能发生在单个实体上。

一般的例子是:汽车有很多车轮。对于每辆车我都想得到每一个轮子。

Select * from cars
Select * from wheels where carId=?

List<Car> cars = getCarsFromDB();
for(Car car : cars){
   List<Wheel> wheels = car.getWheels(); //Wheels are entities.
}

但是非实体呢?:

List<Car> cars = getCarsFromDB();
for(Car car : cars){
   //select car.plate from Car car where car.id = ?
   String plate = car.getPlate(); //Plate is just a varchar.
}

JPA是否还懒惰获取非实体? 这也是N + 1问题吗?

1 个答案:

答案 0 :(得分:2)

简短的回答,取决于。

如果您没有使用Hibernate的字节码增强功能,那么当您加载实体时,任何基本类型的列都会自动获取,因此它们不会变得懒惰,也不会引入额外的查询使它们可用。

因此,在您的情况下,在创建Car实例时填充板。

现在,如果您正在使用Hibernate的字节码增强功能并且您专门注释该字段为@Lazy,那么该字段是惰性的,当您访问该字段时会产生数据库查询成本这是第一次,就像一个懒惰的协会。

在这种情况下,你可以做些什么来避免N + 1问题(这里N是每个延迟注释字段),你可以指定@LazyGroup并将一些惰性初始化字段组合在一起,这样当一个在访问组中,其余部分将同时加载。

但同样,上面描述的后一种情况仅适用于您使用字节码增强功能以​​及专门指定要延迟加载字段时。

JPA Specific

JPA规范声明如下:

  

3.2.9:

     

如果所有属性都使用FetchType.EAGER,则认为实体已加载 - 无论是否明确   指定或默认 - (包括关系和其他集合值属性)已经   从数据库加载或由应用程序分配。具有FetchType.LAZY的属性可以或   可能没有加载。实体实例和关联实例的可用状态为   在3.2.7节中描述。​​

     

如果加载了embeddable属性,则认为可以加载可嵌入的属性   从数据库或由应用程序分配,如果属性引用可嵌入的实例   (即,不为空),已知可加载的实例状态被加载(即,所有的属性)   使用FetchType.EAGER嵌入已从数据库加载或由应用程序分配   和灰)。

     

...

     

如果基本属性的状态已从数据库加载或由其分配,则认为该基本属性已加载   申请。

因此,假设您从数据库加载了Car实例(例如,它不是您通过#getReference()获得的Car实例),则基本属性被视为已加载&amp;分配