본문 바로가기

분류 전체보기

(21)
N+1 문제와 해결 JPA의 성능 문제 중 70~80% 가 N+1 문제라고 한다. N+1 문제를 해결할 수 있는 방법은 크게 3가지 (Fetch Join, @EntityGraph, @BatchSize) 정도가 있다. @EntityGraph, @BatchSize는 JPA 옵션 같은 느낌이고 사실 Fetch Join만 잘 알아도 나머지를 이해하는데 큰 어려움이 없다. 하지만 Fetch Join을 사용하기 위해서는 여러 주의사항을 알고 있어야 하기 때문에 이를 정리하고자 한다. N+1 문제 N+1 문제는 연관관계가 매핑된 엔티티를 조회할 때 발생하는 문제로 처음 조회된 쿼리 결과를 바탕으로 N번 이상의 쿼리가 더 실행되는 문제를 말한다. 결과만 본다면 Fetch Join을 사용한 쿼리와 동일한 데이터를 갖고 있어 정상으로 보일 ..
Lazy Loading과 Dirty Checking 응용 Lazy Loading(지연 로딩)은 연관관계가 매핑된 엔티티를 조회했을 때 조회한 해당 엔티티의 데이터만 가져오는 걸 뜻한다. 조회하지 않은 엔티티는 get 메서드 호출 시 영속성 컨텍스트를 비교 후 값이 없다고 판단하면 그때서야 데이터를 가져온다. Dirty Checking(변경 감지)은 영속성 컨텍스트에서 관리하는 엔티티의 값이 변경되었을 경우 1차 캐시 안의 스냅샷과 비교 후 변경을 감지하고, Update 쿼리를 만들어 트랜잭션 커밋 시점에 update 처리를 해준다. 이론적으론 알고 있지만 언제 사용하면 좋을지 고민하였는데, JPA를 사용해보지 않은 나에게 좋은 예제가 있어 글을 남겨본다. 엔티티 구현 각 엔티티 간의 간략한 관계도를 그려봤다. Order를 중심으로 Delivery와 1:1 양방..
엔티티 생명주기와 영속성 컨텍스트 엔티티 생명주기 먼저 엔티티의 생명주기를 알아야 영속성 컨텍스트를 이해할 수 있고 JPA의 특징을 살려 개발을 할 수 있게 된다. @Entity를 적용한 클래스만이 엔티티가 될 수 있으며, 엔티티의 생명주기는 비영속(New), 영속(Managed), 준영속(Detached), 삭제(Removed)로 구분된다. 이 중에서 영속 상태에서만 영속성 컨텍스트의 관리 대상이 된다. 비영속 //비영속 상태 Member member = new Member(); member.setName("member"); member.setAddress(new Address("한국", "서울", "12345")); //준영속 상태로 변경 //실제 DB에 들어갈 수 있는 식별자를 사용해야 영속으로 변경 가능 member.setid(1..
엔티티 매니저 팩토리와 엔티티 매니저 EntityManagerFactory 엔티티 매니저 팩토리의 주요 역할은 엔티티 매니저가 인스턴스화 되도록 지원하는 것이다. 엔티티 매니저 팩토리는 하나의 데이터베이스를 위해 구성되며 리소스를 효율적으로 관리(커넥션 풀 관리 등)함으로써 해당 데이터베이스에 대해 여러 엔티티 매니저를 구성하는 효율적인 방법을 제공한다. 생성 비용이 크기 때문에 한 번 생성 후 재사용되며 Thread-Safe 하게 구현되어 있어 구성된 전체 애플리케이션을 지원할 수 있다. 애플리케이션을 종료할 때는 반드시 종료해주어야 하며 엔티티 매니저 팩토리가 종료되면서 엔티티 매니저들도 함께 종료된다. 생성 시점에는 persistence.xml 파일에 설정된 정보를 읽어온다. persistence.xml 설정 정보 설정 정보는 버전에 ..
@Transactional 적용 스프링 프레임워크는 @Transactional 을 제공해 비즈니스 로직에 들어있는 JDBC 기술을 걷어내 서비스 계층을 특정 기술에 종속되지 않도록 하였고 다양한 옵션을 통해 트랜잭션을 제어할 수 있다. @Transactional 적용 전 @Slf4j @RequiredArgsConstructor public class MemberService { private final DataSource dataSource; private final MemberRepository memberRepository; public void transfer(String fromId, String toId, int money) throws SQLException { Connection con = dataSource.getConn..
의존관계 주입 의존관계 주입 의존관계 주입은 런타임 시점에 스프링 컨테이너에 등록된 빈을 @Autowired가 적용된 필드에 주입하여 구현체를 직접 생성하지 않아도 사용이 가능하게끔 하는 것이다. 주입받은 코드는 구현체를 직접적으로 생성하지 않았기 때문에 OCP, DIP를 지킬 수 있다. 의존관계 주입은 크게 생성자 주입, 수정자 주입(setter 주입), 필드 주입이 있다. 기본적으로 스프링은 빈을 먼저 등록 후 의존관계 주입을 하지만, 생성자 주입의 경우 빈 등록 전 객체를 생성하고 의존관계를 주입 후 등록하는 예외가 있다. 생성자 주입 @Component public class OrderServiceImpl implements OrderService { private final MemberRepository me..
@Repository 기능 @Repository 는 데이터 액세스 계층에서 사용되는 애너테이션이다. 보통은 컴포넌트 스캔의 대상이 되기 위해 적용하지만 스프링 부트와 JPA 를 사용할 경우 예외 변환기(PersistenceExceptionTranslationPostProcessor) 를 자동으로 등록해서 @Repository 를 적용한 빈을 프록시로 변환한다. 이렇게 변환된 프록시는 데이터 액세스 계층에서 예외가 발생하면 스프링 예외 추상화(DataAccessException)로 변환해준다. 스프링 예외 추상화로 변환 시 이점은 JPA 뿐만 아니라 JdbcTemplete, MyBatis 와 같은 데이터 접근 기술에서 발생되는 예외를 통합적으로 관리한다는 점이다. 따라서 데이터 접근 기술을 변경하더라도 예외 처리하는 로직을 수정할 ..