Too many queries problem with JPA + Hibernate even when using @Fetch(FetchMode.JOIN)

koushikmln :

I am developing REST application using spring boot and I am trying to optimize the performance of the queries. I am currently using findAll from the repositories which is causing performance issues. Code is given below:

Person Entity

@Entity
@Table(name = "cd_person")
@Data
@NoArgsConstructor
public class Person {
    ....
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "password_id")
    @Fetch(FetchMode.JOIN)
    private Password password;
    ....
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "cd_person_role",
        joinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    @Fetch(FetchMode.JOIN)
    private Set<Role> roles = new HashSet<>();
}

Password Entity

@Entity
@Table(name = "cd_password")
@Data
@NoArgsConstructor
public class Password {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @Column(name = "password_hash", nullable = false)
    private String passwordHash;
    .......
}

Role Entity

@Entity
@Table(name = "cd_role")
@Data
@NoArgsConstructor
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "role_type")
    @Enumerated(EnumType.STRING)
    private RoleType roleType;
    ....
}

Person Repository

public interface PersonRepository extends CrudRepository<Person, Long> {

    Optional<Person> findByEmail(String email);

}

When I do a personRepository.findAll() there are select queries fired for each row in the person table to fetch the password and roles when I access the person. I know I can use @Query annotation with JOIN FETCH in the repository to make it force generate the single query but I was wondering if there was any other way to do so. I am looking for something which we can do at the entity level to reduce queries.

Using spring boot 2.1.5-RELEASE version and related dependencies.

PS. The @Data and @NoArgsConstructor are Lombok annotations.

Ken Chan :

The most minimal code change is to use the ad-hoc EntityGraph feature from spring data . Just override PersonRepository 's findAll() and use @EntityGraph to configure the graph. All entities in this graph will be fetched together.

public interface PersonRepository extends CrudRepository<Person, Long> {

    @EntityGraph(attributePaths = { "password", "roles" })
    public List<Person> findAll();

}

Behind scene it works like JOIN FETCH. Only single SQL with LEFT JOIN will be generated.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=139282&siteId=1