[英]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.