JPA 是否也对原始属性懒惰?

Is JPA also lazy for primitive attributes?

我正在尝试检测代码中的 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问题吗?

简短的回答,视情况而定。

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

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

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

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

但同样,我上面描述的后一种情况仅在您使用字节码增强并且当您特别指定要延迟加载字段时适用。

JPA 特定

JPA 规范规定如下:

3.2.9:

An entity is considered to be loaded if all attributes with FetchType.EAGER—whether explictly specified or by default—(including relationship and other collection-valued attributes) have been loaded from the database or assigned by the application. Attributes with FetchType.LAZY may or may not have been loaded. The available state of the entity instance and associated instances is as described in section 3.2.7.

An attribute that is an embeddable is considered to be loaded if the embeddable attribute was loaded from the database or assigned by the application, and, if the attribute references an embeddable instance (i.e., is not null), the embeddable instance state is known to be loaded (i.e., all attributes of the embeddable with FetchType.EAGER have been loaded from the database or assigned by the applica- tion).

...

A basic attribute is considered to be loaded if its state has been loaded from the database or assigned by the application.

因此假设您有一个从数据库加载的 Car 实例(例如,它不是您通过 #getReference() 获得的 Car 实例),基本属性被视为已加载和分配。