简体   繁体   English

Hibernate:@OneToOne 的 N+1 修复

[英]Hibernate: N+1 fix for @OneToOne

I have @OneToOne relationship with classes:我与类有@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...
}

Address:地址:

@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...
}

I have a default JpaRepository for person:我有一个默认的JpaRepository for person:

@Repository
public interface PersonRepository
    extends JpaRepository<Person, Long> {
}

And when i calling repository.findAll() i taking n+1 problem:当我调用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=?

How i can fix that?我该如何解决? (I want fetching with JOIN like this example: SELECT * FROM persons INNER JOIN address ON person.address_id = address.id ) (我想像这个例子一样用 JOIN 获取: SELECT * FROM persons INNER JOIN address ON person.address_id = address.id

Solved by adding @Query annotation:通过添加@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();
}

Maybe that's not best solution (if we will adding more properties to object we need update query everytime) but thats work very fine:也许这不是最好的解决方案(如果我们将向对象添加更多属性,我们每次都需要更新查询)但那工作得很好:

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

Solved by adding @Query annotation:通过添加@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();
}

Now that's looks like:现在看起来像:

    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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM