페치 전략에 따라도 다르지만 영속성 컨텍스트에 어떻게 추가하는지에 따라 또 달라집니다. EAGER Fetch EntityManager.find() find 메소드와 EAGER 페치전략을 사용하면 inner join으로 N+1문제 없이 주로 같이 조회가 되는 연관관계의 경우에 사용할 수 있습니다. EntityManger.createQuery() EAGER 페치전략을 사용해도 EntityManger.createQuery(JPQL)를 사용하면 한 번의 쿼리에 정보를 모두 가져오지 않지만 EAGER 페치전략을 사용하기 때문에 곧바로 N+1 문제가 터집니다. Spring Data JPA JpaRepository의 기본구현체인 SimpleJpaRepository의 findById 와 findAll, 커스텀 find..
사실 JPA 고수 아닙니다. 자바 백엔드 시작을 김영한님의 강의를 보고 시작한만큼 DB접근 기술을 JPA밖에 몰랐었고, 올해 초에 프로그래머스에서 진행한 단순 CRUD 구현을 그만 ! 스터디를 들으면서 JDBC Template를 써보긴했지만 스터디 커리큘럼을 따라가면서도 테이블 정의하는 것과 PrepareStatment로 쿼리짜는 게 귀찮아 DBA의 튜닝 쿼리를 빠르게 적용할 수 있겠다는 장점만 기억하는 것과 JPA를 쓰고 싶다는 생각만 했었던 것 같습니다. JPA를 한번 더 추상화한 스프링 데이터 JPA를 사용하면서 얼마나 많은 부분이 추상화된지 이론적으로 공부는 했지만 마이바티스를 다뤄보면서 직접 테이블 생성과 쿼리를 짜며 프로젝트를 진행하며 사용한 후기를 정리합니다. Mybatis-Spring ..
SQLMapper를 대충 경험하고 JPA를 시작해서 요즘 들어깨닫는게 많다. N+1 문제가 발생하는 원인과 해결하는 법을 알았는데 그 이전에 JPA를 SQLMapper처럼 사용할줄 알고(단방향 연관관계 사용) 필요할 때 양방향 연관관계를 사용해야한다는 걸 알았고 정리하려고 글을 쓴다. JPA 단방향 연관관계 DB설계에서 글과 댓글은 1:N의 관계를 갖는다. 이때 댓글은 글의 id를 외래키로 가진다. 그럼 예시와 같은 글과 댓글의 화면을 렌더링 해주려면 해당 글과 해당 글의 댓글을 가져와야한다. 글은 View 렌더링으로, 댓글은 Ajax로 해당 글의 id를 통해 비동기로 가져오는 서비스의 흐름을 가진다면 Entity @Entity @Getter @NoArgsConstructor @AllArgsConstru..
가장 중요한 것은 필요한 정보만큼의 쿼리를 날리는 것이다. 조인을 하지 않고 너무 적은 정보를 가져와 발생하는 예상하기 어려운 N+1 문제도, 서비스 동작시에 필요없는 정보도 조인으로 가져오는 것도 문제다. 같은 객체를 DB에서 가져오더라도, 필요한 정보의 양이 다르면 메소드를 분리해야 한다. EntityGraph를 사용하든 Fetch Join을 사용하든 서비스에서 필요한 정보의 양은 서비스의 동작 마다 다르다. 코드 예시를 보자 Team Entity @Entity @Getter @NamedEntityGraph(name = "Team.withAll", attributeNodes = { @NamedAttributeNode("tags"), @NamedAttributeNode("zones"), @NamedAt..
트랜잭션의 범위와 영속성 컨텍스트의 범위는 별개 짧게 결과만 말하자면 위와 같다. 지금까지 트랜잭션의 범위 == 영속성 컨텍스트의 범위라고 알고 사용해서 종종 느껴지는 이게 왜 되는건지에 대한 문제가 OSIV 때문이였다. OSIV 설명 전에 엔티티의 생명주기 먼저 복습하고 간다. 엔티티의 생명주기 비영속 transient 객체를 생성하고 영속성 컨텍스트가 관리는 안하는 상태 보통의 경우 엔티티 식별자(id)를 DB에 맡기기 때문에 아직 식별자가 존재하지 않는다. 영속 managed 영속성 컨텍스트에 저장된 상태 비영속 엔티티를 persist 하거나 DB의 엔티티를 find 시 영속성 컨텍스트에 영속된다. 준영속 detached 영속성 컨텍스트에 저장되었다가 분리된 상태 저장되었던 적 있기 때문에 엔티티 ..
@Basic @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Basic { /** * (Optional) Defines whether the value of the field or property should * be lazily loaded or must be eagerly fetched. The EAGER * strategy is a requirement on the persistence provider runtime * that the value must be eagerly fetched. The LAZY * strategy is a hint to the persistence provider runtime. * If not specif..
N+1 문제 이전에 김영한님의 JPA 강의 중 연관관계 어노테이션에 @XToOne에 Fetch.Type을 LAZY를 추천한다. @XToMany는 기본으로 LAZY가 걸려있지만 @XToOne은 EAGER가 걸려 SELCT 하는 엔티티가 참조하는 엔티티도 모두 불러오기 때문이다. 참조 타입을 LAZY로 걸고 해당 엔티티를 사용하지 않으면 N+1 문제를 발생하는 쿼리를 발생시키지 않지만 LAZY를 걸어도 해당 엔티티를 사용하면 엔티티 프록시 객체는 모든 값을 가지고 있지 않기 때문에 값을 가져오기 위해 (영속성 컨텍스트,DB)로 N+1 문제를 발생하는 쿼리를 날린다. Join, Fetch Join Spring Data JPA가 제공해주는 것 외에도 JPQL을 사용해야하는 경우엔 @Query를 사용한다. JPQ..