我有一个使用Hibernate作为JPA提供者的Spring Boot应用程序。我的应用程序有两个与@OneToMany
/@ManyToOne
关系连接的实体。在两个方向上都标注了@Fetch(FetchMode.JOIN)
和fetch = FetchType.EAGER
的关系。
我的实体被称为Car
和Driver
:
@Entity
@Table(name = "car")
@Data
public class Car implements Serializable, Cloneable {
@Id
@GenericGenerator(name = "car_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
@Parameter(name = "sequence_name", value = "car_seq") })
@GeneratedValue(generator = "car_seq")
private Integer id;
@OneToMany(mappedBy = "car", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private List<Driver> drivers = new ArrayList<>();
@Column(name = "license_no", nullable = false)
private String licenseNo;
}
@Entity
@Table(name = "driver")
@Data
public class Driver implements Serializable, Cloneable {
@Id
@GenericGenerator(name = "driver_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
@Parameter(name = "sequence_name", value = "driver_seq") })
@GeneratedValue(generator = "driver_seq")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "car_id", nullable = true)
@Fetch(FetchMode.JOIN)
private Car car;
@Column(name = "name", nullable = false)
private String name;
}
当选择一个care(例如通过调用Car.findById()
)时,Hibernate在一个SQL中连接两个表,并返回一个Car
对象和一个Drivers
列表。
但是,如果我选择一个驱动程序,Hibernate将连接Driver
和Car
表,以给我Driver
对象,并填充Car
属性,但它将运行第二个查询来获取汽车对象列表上的所有驱动程序对象。
出于性能原因,我希望在单个查询中获取所有涉及的对象,就像我获取汽车的情况一样。但是我找不到让Hibernate做到这一点的方法。有一个属性,hibernate.max_fetch_depth
,应该这样做,但我发现它只影响取车的行为,而不是当我取司机。
我知道我可以使用EntityGraph
来控制抓取,并且通过使用EntityGraph
,我已经成功地在一个查询中检索了具有其汽车和所有汽车驾驶员的驾驶员对象。但是要做到这一点,我必须在检索对象时显式地使用图,并且我不能在需要Car
对象的所有各种情况下都这样做。还有很多其他实体与Car
有关系,我不想为每一个实体都写一个EntityGraph
。
那么是否有一种方法可以告诉Hibernate您希望如何在默认情况下对实体进行抓取?我本以为有注释就足够了,但似乎还需要更多的东西,或者根本无法做到这一点。
阿恩特
FetchType.EAGER
是性能问题最常见的原因之一。你应该使用
@OneToMany(mappedBy = "car")
private List<Driver> drivers = new ArrayList<>();
和获取驱动程序如果需要
SELECT c FROM Car c JOIN FETCH c.drivers