[JPA]即時ロード(Eager)と遅延ロード(Lazy)


Webプロジェクトの実行中に双方向マッピング関係におけるN+1の問題に遭遇した.
N+1問題の原因と解決策の前に,即時ロードと遅延ロードを理解すべきであると考えられる.

即時ロードと遅延ロード


即時ロードと遅延ロードは、2つの双方向マッピングがあるEntityを指定し、1つのEntityをクエリーするときにマッピングされたEntityを同時にクエリーするか、実際のマッピングが必要なEntityクエリーをクエリーするときにクエリーするかを指定します.
ビジネスロジックでは、特定のエンティティに関連するロジックのみが使用され、マッピングされたエンティティにクエリーされると効率が低下します.この問題は、JPAがプロキシクエリを介して遅延ロードを使用して解決します.
次の例について詳しく説明します.

ディレイロード

@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    private String password;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private List<Post> postList;
}
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private String content;

    private String writer;

    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}
  • ユーザー、Post Entity、およびPost Entityを問い合わせるロジックがある場合、Post Entityのロード時にLazyロードに設定されたユーザーEntityがFreshオブジェクトにインポートされます.
  • 以降、クエリは実際のオブジェクトを使用するときに実行されます.
  • getUser()関数を使用してユーザーを問い合わせると、プロキシオブジェクトが問い合わされます.
  • getUser().getXXX()関数を使用してユーザーフィールドにアクセスすると、クエリーが実行されます.
  • ほとんどの論理で2つのEntityが同時に使用されている場合、Lazyを使用すると2回のselectクエリが実行されます.
    これは、非常に遅いディスクに2回アクセスする必要があるため、非常に効率的ではありません.
    この場合、「即時ロード」(Eager)を使用して2つのEntityを一緒にクエリーすることが有効です.

    即時ロード(Eager)

    @Entity
    @AllArgsConstructor
    @Getter
    @Setter
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        private String email;
    
        private String password;
    
        @OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
        private List<Post> postList;
    }
    @Entity
    @AllArgsConstructor
    @Getter
    @Setter
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public class Post {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String title;
    
        private String content;
    
        private String writer;
    
        @ManyToOne(fetch = FetchType.EAGER)
        private User user;
    }
    遅延ロードとは異なり、
  • は、プロキシオブジェクトではなく結合を使用してマッピングされたEntityを同時にクエリーするときにロードします.
  • の場合は、すぐにロードを使用しないほうがいいです.
  • がすぐにロードされると、JPQLにN+1の問題が発生します.(遅延ロードを使用するとN+1に問題が発生しないという意味ではありません...他の方法で解決する必要があります)
    N+1問題については,次の位置決めを行う.