我正在尝试检测代码中的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问题吗?
答案 0 :(得分:2)
简短的回答,取决于。
如果您没有使用Hibernate的字节码增强功能,那么当您加载实体时,任何基本类型的列都会自动获取,因此它们不会变得懒惰,也不会引入额外的查询使它们可用。
因此,在您的情况下,在创建Car
实例时填充板。
现在,如果您正在使用Hibernate的字节码增强功能并且您专门注释该字段为@Lazy
,那么该字段是惰性的,当您访问该字段时会产生数据库查询成本这是第一次,就像一个懒惰的协会。
在这种情况下,你可以做些什么来避免N + 1问题(这里N是每个延迟注释字段),你可以指定@LazyGroup
并将一些惰性初始化字段组合在一起,这样当一个在访问组中,其余部分将同时加载。
但同样,上面描述的后一种情况仅适用于您使用字节码增强功能以及专门指定要延迟加载字段时。
JPA规范声明如下:
3.2.9:
如果所有属性都使用FetchType.EAGER,则认为实体已加载 - 无论是否明确 指定或默认 - (包括关系和其他集合值属性)已经 从数据库加载或由应用程序分配。具有FetchType.LAZY的属性可以或 可能没有加载。实体实例和关联实例的可用状态为 在3.2.7节中描述。
如果加载了embeddable属性,则认为可以加载可嵌入的属性 从数据库或由应用程序分配,如果属性引用可嵌入的实例 (即,不为空),已知可加载的实例状态被加载(即,所有的属性) 使用FetchType.EAGER嵌入已从数据库加载或由应用程序分配 和灰)。
...
如果基本属性的状态已从数据库加载或由其分配,则认为该基本属性已加载 申请。
因此,假设您从数据库加载了Car
实例(例如,它不是您通过#getReference()
获得的Car实例),则基本属性被视为已加载&amp;分配