Post

JPA 사용 메모

JPA 사용 중 참고할 만한 내용을 기록하는 메모장

JPA 사용 메모

N+1 문제

  • n + 1 문제는 JPA에서 발생하는 성능 문제 중 하나로, 연관관계 매핑을 잘못하면 발생할 수 있다.
  • 예를 들어, Member와 Team이 일대다 관계로 매핑되어 있을 때, Member를 조회할 때 Team을 함께 조회하면 N+1 문제가 발생할 수 있다.
  • fetch join, entity graph, batch size 등을 별도로 설정하여 해결할 수 있다.

직접참조 vs 간접참조

  • 직접참조 - @ManyToOne, @OneToOne 등의 연관 어노테이션을 사용하여 직접 참조하는 방식
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @Entity
    public class Member {
      @Id @GeneratedValue
      private Long id;
      private String name;
      @ManyToOne
      @JoinColumn(name = "team_id")
      private Team team;
    }
    
  • 간접참조 - db에서 사용하는 외래키 컬럼을 직접 컬럼으로 매핑하는 방식
    1
    2
    3
    4
    5
    6
    7
    8
    
    @Entity
    public class Member {
      @Id @GeneratedValue
      private Long id;
      private String name;
      @Column(name = "team_id")
      private Long teamId;
    }
    

    직접참조하는 방식을 사용하면 객체 간 관계를 명확하게 표현할 수 있으나, 복잡도가 증가할 수 있다. 반면, 간접참조 방식을 사용하면 유연성 증가, 성능 향상, 복잡도 감소 등의 장점이 있다.

hibernate cache

1st level cache

  • Hibernate의 기본 캐시이며, 별도 설정 없이 자동으로 활성화됨.
  • Session 단위로 존재하며, 동일한 Session 내에서는 동일한 엔티티 조회 시 DB 쿼리를 수행하지 않음.
  • 트랜잭션이 종료되면 캐시가 사라짐 (지속되지 않음).
1
2
3
4
5
Session session = sessionFactory.openSession();
Member member1 = session.get(Member.class, 1L);  // 첫 번째 조회 (DB 쿼리 발생)
Mjember member2 = session.get(Member.class, 1L); // 두 번째 조회 (DB 쿼리 발생 X, 캐시에서 가져옴)

System.out.println(member1 == member2);  // true (같은 객체)

2nd level cache

  • 여러 Session 간 데이터를 공유할 수 있는 캐시.
  • 세션을 종료해도 캐시가 유지되어 다음 세션에서 재사용 가능.
  • 기본적으로 비활성화되어 있으며, EHCache, Redis, Infinispan 등의 외부 캐시 저장소를 사용해야 함.
  • Entity 단위 캐시, Query 캐시, Collection 캐시를 설정할 수 있음.
  • @Cacheable 어노테이션을 적용하여 선택적으로 캐싱 가능.
  • 자주 변경되지 않는 데이터라면 2nd level cache를 사용하여 성능 향상을 기대할 수 있음.

element collection

  • 맵핑할 정보가 엔티티와 동일한 생명주기를 가질 때 사용한다. (vs @ManyToOne » 엔티티와 독립적인 별도 생명주기를 가질 때 사용)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    @Entity
    public class Member {
      @Id @GeneratedValue
      private Long id;
      private String name;
      @ElementCollection
      @CollectionTable(name = "tbl_favorite_foods", joinColumns = @JoinColumn(name = "member_id"))
      @Column(name = "food_name")
      private Set<String> favoriteFoods = new HashSet<>(); // List, Map 등도 사용 가능
    }
    

중첩 참조

  • a->b->c->d->e 와 같이 꼬리를 물고 참조는 복잡도를 높인다. 되도록이면 참조를 단순하게 하는 것이 좋다.

    참조를 (a->c->e) + (a->b, c->d) 와 같이 분리하면 복잡도를 낮출 수 있다.

Specification

This post is licensed under CC BY 4.0 by the author.