728x90
프록시와 연관관계
- 지연 로딩: 연관된 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법
- 프록시: 지연 로딩 기능을 사용하려면 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데, 이를 프록시 객체라고 함
- Member member = em.find(Member.class, "member1");
- 이렇게 엔티티를 직접 조회하면 조회한 엔티티를 실제 사용하지 않아도 데이터베이스를 조회(영속성 컨텍스트에 엔티티가 없는 경우)
- Member member = em.getReference(Member.class, "member1");
- JPA는 데이터베이스를 조회하지 않고 실제 엔티티 객체도 생성하지 않음
- 대신 데이터베이스 접근을 위임한 프록시 객체를 반환
- Member member = em.find(Member.class, "member1");
- 프록시의 특징
- 실제 클래스를 상속받아서 만들어짐
- 실제 객체에 대한 참조(target)을 보관
- 프록시 객체의 메소드를 호출하면 프록시 객체는 실제 객체의 메소드를 호출
- 프록시 객체의 초기화
- 프록시 객체는 실제 사용될 때 데이터베이스를 조회해서 실제 엔티티 객체를 생성
- 처음 사용될 때 한 번만 초기화됨
- 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근할 수 있음
- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 프록시가 아닌 실제 엔티티를 반환
- 초기화는 영속성 컨텍스트의 도움을 받아야 가능. 준영속 상태의 프록시를 초기화하면 문제가 발생.
- 하이버네이트는 org.hibernate.LazyInitializationException 예외를 발생시킴
- 추천하는 방법은 모든 연관관계에 지연 로딩을 사용하는 것 -> 어느정도 완성한 후 꼭 필요한 곳에만 즉시 로딩을 사용하도록 최적화 !
영속성 전이: CASCADE
- 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이 기능을 사용
- JPA는 CASCADE 옵션으로 영속성 전이를 제공 - 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장 가능
- JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.
- 영속성 전이: 저장
- Parent.class에서 cascade = CascadeType.PERSIST 설정
- child1.setParent(parent);
- child2.setParent(parent);
- em.persist(parent); //부모 저장, 연관된 자식들 저장
- 엔티티를 영속화할 때 연관된 엔티티도 같이 영속화하는 편리함을 제공
- 연관관계를 매핑하는 것과 관련 없음
- Parent.class에서 cascade = CascadeType.PERSIST 설정
- 영속성 전이: 삭제
- 부모와 지식 엔티티를 모두 제거하려면 하나씩 제거해야 함
- cascade = CascadeType.REMOVE 설정
- Parent findParent = em.find(Parent.class, 1L);
- em.remove(findParent);
- 자식을 먼저 삭제하고 부모를 삭제
- 영속성 전이: 저장
- 고아 객체 제거 : JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공
- 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티틱가 자동으로 삭제됨
- Parent.class에서 orphanRemoval = true 설정
- Parent parent1 = em.find(Parent.class, id);
- parent1.getChildren().remove(0); // 자식 엔티티를 컬렉션에서 제거
- 제거된 자식 엔티티는 자동으로 삭제됨
- 이 기능은 참조하는 곳이 하나일 때만 사용해야 함
- 따라서 orphanRemoval은 @OneToOne, @OneToMany에만 사용할 수 있다.
- 고아 객체 제거는 부모를 제거하면 자식이 고아가 되므로 자식도 함께 제거된다. 이것은 CascadeType.REMOVE를 설정한 것과 같다.
- 영속성 전이 + 고아 객체
- CascadeType.ALL + orphanRemoval = true
- 부모 엔티티를 통해서 자식의 생명주기를 관리
- 자식을 저장하려면 부모에 등록만 하면 된다.
- 자식을 삭제하려면 부모에서 제거하면 된다.
스프링 데이터 JPA
- SpringBoot 환경에서는 EntityManagerFactory와 EntityManager를 자동으로 생성
- application.properties에 DB 정보를 전달해주면 이를 토대로 EntityManagerFactory가 생성
- @PersistenceContext 애너테이션을 사용하면 자동으로 생성된 EntityManager를 주입받아 사용할 수 있음
@PersistenceContext
EntityManager em;
- Spring의 트랜잭션
- @Transactional 애너테이션을 클래스나 메서드에 추가하면 트랜잭션 개념을 적용할 수 있음
- readOnly = true 옵션: 트랜잭션에서 데이터를 읽기만 할 때 사용. 읽기 작업에 대한 최적화를 수행.
- JPA를 사용하여 DB에 데이터를 저장, 수정, 삭제 하려면 트랜잭션 적용이 반드시 필요
- 트랜잭션 전파
- 기본 옵션은 REQUIRED: 부모 메서드에 트랜잭션이 존재하면 자식 매서드의 트랜잭션은 부모 트랜잭션에 합류
- 스프링 컨테이너의 기본 전략
- 트랜잭션의 범위와 영속성 컨텍스트의 생존 범위가 같다.
- 보통 서비스 계층에 @Transactional 어노테이션을 선언해서 트랜잭션을 시작
- 트랜잭션이 같으면 엔티티 매니저가 달라도 같은 영속성 컨텍스트를 사용한다.
- 트랜잭션이 다르면 엔티티 매니저가 같아도 다른 영속성 컨텍스트를 사용한다.
- 컨트롤러 로직(준영속 상태)에서 지연 로딩 시 예외 발생
- 뷰가 필요한 엔티티를 미리 로딩해두는 방법
- 글로벌 페치 전략 수정: 즉시 로딩으로 변경
- 단점: 사용하지 않는 엔티티를 로딩, N+1 문제 발생
- JPQL 패치 조인: N+1 문제 해결
- 단점: 프리젠테이션 계층이 데이터 접근 계층을 침범
- 강제로 초기화
- order.getMember().getName(); // 프록시 객체를 강제로 초기화
- 하이버네이트 사용: org.hibernate.Hibernate.initialize(order.getMember()); // 프록시 초기화
- 프록시 초기화 역할을 서비스 계층이 담당하면 뷰가 필요한 엔티티에 따라 서비스 계층의 로직을 변경해야 함 : 프리젠테이션 계층이 서비스 계층을 침범하는 상황
- 서비스 계층에서 프리젠테이션 계층을 위한 프록시 초기화 역할을을 분리해야 함 -> FACADE 계층 추가
- 글로벌 페치 전략 수정: 즉시 로딩으로 변경
- OSIV를 사용해서 엔티티를 항상 영속 상태로 유지하는 방법
- 영속성 컨텍스트를 뷰까지 살아있게 열어둠으로써 지연 로딩을 뷰에서도 사용 가능하게 함
- 스프링 프레임워크가 제공하는 OSIV 라이브러리
- 동작 원리
- 클라이언트의 요청이 들어오면 서블릿 필터나 스프링 인터셉터에서 영속성 컨텍스트를 생성
- 서비스 계층에서 트랜잭션을 시작하면 앞에서 생성해둔 영속성 컨텍스트에 트랜잭션을 시작
- 서비스 계층이 끝나면 영속성 컨텍스트를 플러시한다. 이때 트랜잭션만 종료하고 영속성 컨텍스트를 살려둔다.
- 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지
- 서블릿 필터나 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료. 이때 플러시를 호출하지 않고 바로 종료.
- 영속성 컨텍스트는 트랜잭션 범위 안에서 엔티티를 조회하고 수정할 수 있다.
- 영속성 컨텍스트는 트랜잭션 범위 밖에서 엔티티를 조회만 할 수 있다. = 트랜잭션 없이 읽기
- 뷰가 필요한 엔티티를 미리 로딩해두는 방법
'TIL' 카테고리의 다른 글
[231201] JPA와 영속성 컨텍스트 (0) | 2023.12.01 |
---|---|
[231130] 팀과제 수정 (0) | 2023.11.30 |
[231128] Spring 숙련주차 팀과제, JPA 연관관계 (0) | 2023.11.28 |
[231122] ResponseDto, RequestDto에 Getter가 필요한 이유 (0) | 2023.11.22 |
[231120] Spring 숙련주차 개인과제 해설 (0) | 2023.11.20 |