classDiagram
direction TB
Post --> "Many (*)" PostComment
If you want to fetch Post and its comments then following queries will fire
1 Query to fetch list of posts
N Queries to fetch post comments for each post, where N = # of Posts
Use FetchType.LAZY, by default @OneToMany() and @ManyToOne() are FetchType.EAGER
@Entity(name = "Post")@Table(name = "post")public class Post { @Id private Long id; private String title;}@Entity(name = "PostComment")@Table(name = "post_comment")public class PostComment { @Id private Long id; @ManyToOne(fetch = FetchType.LAZY) // Here we are using lazy fetch type private Post post; private String review;}
Even if you do Lazy Fetch Type, you will still run into issues if you try to access post_comments
Hence neither Lazy Fetch type nor Eager Fetch Type solves the N+1 problem completely
Best way is to create separate methods, SQL and JPQL queries to tailor them for each case.
classDiagram
direction TB
Department --> "Many (*)"Employee
class Department { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "dept_id") List<Employee> listOfEmployees;}
Spring Data approach
using left join fetch
FETCH is JPA-specific statement
FETCH works on both JOIN and LEFT JOIN statements
instructs persistence provider to do both:
join the two database tables contained in the query
initialize the association on the returned entity
interface DepartmentRepository extends JpaRepository<Department, Long> { @Query("SELECT p FROM Department p LEFT JOIN FETCH p.listOfEmployee) List<Department> findWithoutNPlusOne();}/* * Internally it will hit single SQL query like this * * select dept.id, dept.name, * emp.id, emp.name, emp.dept_id * from * dept_table dept * left join * employee_table emp * on dept.id=emp.dept_id * */
using attributePaths
aka EntityGraphs
allow partial or specific fetching of objects
When an entity (ex. Department) has references to other entities (ex. list of Employee) we can specify a fetch plan by EntityGraphs in order to determine which fields or properties should be fetched together.
interface DepartmentRepository extends JpaRepository<Department, Long> { @EntityGraph(attributesPath = {"listOfEmployees"}) List<Department> findAll();}/* * The findAll() is a customized one and has entity graph defined * * Internally it will hit single SQL query similar to join fetch: * * select dept.id, dept.name, * emp.id, emp.name, emp.dept_id * from * dept_table dept * left join * employee_table emp * on dept.id=emp.dept_id */
Hibernate approach
using HQL Query - “from Department d join fetch d.listOfEmployees Employee”