[英]Hibernate: N+1 fix for @OneToOne
我與類有@OneToOne
關系:
@Entity
@Table(name = "persons", schema = "persons_info")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name",
nullable = false)
@JsonProperty("first_name")
private String firstName;
@Column(name = "last_name",
nullable = false)
@JsonProperty("last_name")
private String lastName;
@Basic
@Column(name = "birth_date", nullable = false)
private Date birthDate;
@OneToOne(cascade = CascadeType.ALL,
orphanRemoval = true)
@JoinColumn(name = "address_id",
referencedColumnName = "id")
private Address address;
// setters, getters, equals...
}
地址:
@Entity
@Table(name = "addresses", schema = "persons_info")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String city;
@Column(nullable = false)
private String street;
@Column(nullable = false)
private String house;
@Column(nullable = false)
private String flat;
@JsonIgnore
@OneToOne(mappedBy = "address")
private Person person;
// setters, getters, equals...
}
我有一個默認的JpaRepository
for person:
@Repository
public interface PersonRepository
extends JpaRepository<Person, Long> {
}
當我調用repository.findAll()
時,我遇到了n+1
問題:
Hibernate:
select
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
p1_0.id,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name,
a1_0.street
from
persons_info.addresses a1_0
left join
persons_info.persons p1_0
on a1_0.id=p1_0.address_id
where
a1_0.id=?
Hibernate:
select
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
p1_0.id,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name,
a1_0.street
from
persons_info.addresses a1_0
left join
persons_info.persons p1_0
on a1_0.id=p1_0.address_id
where
a1_0.id=?
我該如何解決? (我想像這個例子一樣用 JOIN 獲取: SELECT * FROM persons INNER JOIN address ON person.address_id = address.id
)
通過添加@Query
注解解決:
@Repository
public interface PersonRepository
extends JpaRepository<Person, Long> {
@Query(nativeQuery = true,
value = """
SELECT
person.id AS person_id,
person.address_id,
person.first_name,
person.last_name,
person.birth_date,
address.id,
address.city,
address.street,
address.house,
address.flat
FROM persons_info.persons person
INNER JOIN persons_info.addresses address
ON person.address_id = address.id""")
public List<Person> findAll();
}
也許這不是最好的解決方案(如果我們將向對象添加更多屬性,我們每次都需要更新查詢)但那工作得很好:
PersonServiceTest > Find all STANDARD_OUT
Hibernate:
SELECT
person.id AS person_id,
person.address_id,
person.first_name,
person.last_name,
person.birth_date,
address.id,
address.city,
address.street,
address.house,
address.flat
FROM
persons_info.persons person
INNER JOIN
persons_info.addresses address
ON person.address_id = address.id
通過添加@Query注解解決:
@Repository
public interface PersonRepository
extends JpaRepository<Person, Long> {
@Query("""
SELECT p FROM Person p
LEFT JOIN FETCH p.address a""")
public List<Person> findAll();
}
現在看起來像:
Hibernate:
select
p1_0.id,
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
a1_0.street,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name
from
persons_info.persons p1_0
left join
persons_info.addresses a1_0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.