Today I Learned

2024 스파르타 내일배움캠프 Sping 트랙 참여 // day41

shinelee26 2024. 11. 27. 22:43

오늘 진행한 학습 요약

1. Spring 심화 2주차

  • 1 : N 연관관계
  • 1 : 1 연관관계
  • N : M 연관관계
  • 상속관계 매핑
  • Proxy
  • 지연로딩, 즉시로딩
  • 영속성 전이
  • JPA와 Transaction

2. 알고리즘 코드카다  Day43(작성 생략)

CodingTest Git-hub 링크 : https://github.com/chews26/CodingTest

 


학습 정리

1. Spring 심화 2주차

 

1 : N 연관관계

  • 연관관계 매핑
    • JPA 연관관계 매핑을 통해 데이터베이스 테이블 간의 관계를 객체 지향적으로 표현하여 엔티티 클래스들 간의 관계를 설정
    • JPA를 통해 연관관계를 매핑하면 SQL을 직접 작성하지 않고도 객체 간의 관계를 활용하여 쉽게 데이터를 조회하고 조작
      • 연관관계 매핑
        • N:1, 1:N, 1:1, N:M 연관관계
          • N:1 : @ManyToOne
          • 1:N : @OneToMany
          • 1:1 : @OneToOne
          • N:M : @ManyToMany
        • 단방향, 양방향 연관관계
          • 테이블
            • 외래 키(FK) 하나로 모든 테이블 JOIN이 가능
          • 객체
            • 외래키가 있는 객체만 참조가 가능
              • 단방향
              • 참조용 필드가 양쪽에 있는 경우 양방향
              • 단방향 두개로 이루어진 것이 양방향
        • 연관관계의 주인
          • 외래 키(FK)를 관리하는 객체
          • 주인이 아닌 경우 조회만 가능
  • 1 : N 단방향
    • 한 엔티티가 @OneToMany를 통해 여러 엔티티와 관계를 맺는 경우
    • 연관관계의 주인은 1에서 가지고 있음
    • @JoinColumn 을 사용하지 않으면 중간 테이블 방식을 사용하므로 사용 필수
    • 설계가 복잡해져도 N:1 양방향 매핑을 사용하면 관리하기 쉬움
  • 1 : N 양방향
    • 양방향 연관 관계는 하나의 엔티티가 다른 엔티티와 관계를 맺고 그 반대 방향에서도 서로 참조가 가능하도록 설정한 관계
    • 연관관계의 주인이 되지 않도록 insertable = false, updatable = false 설정
    • 1:N 단방향과 같은 이유로 N:1 양방향을 쓰면된다.

1 : 1 연관관계

  • 1 : 1 단방향
    • 두 Entity가 @OneToOne 을 통해 서로 관계를 맺는 경우
    •  
  • 1 : 1 양방향
    • N:1 양방향 연관관계와 유사
    • 1:1 연관관계 양방향
    • 대상 테이블에 외래 키 양방향
    • 1 : 1 연관관계 외래 키
      • 1:1 연관관계에서 외래 키는 양쪽 모두가 관리할 수 있음
      • 둘중 어떤 테이블을 사용해도 무방
      • 단, 테이블은 한번 만들어지면 변경이 어려움
  •  

N : M 연관관계

  • N : M 연관관계
    • 두 Entity가 @ManyToMany를 통해 서로 다수의 관계
    • 관계형 데이터베이스는 N:M 연관관계를 구현할 수 없다
    • 중간 테이블을 추가해서 1:N, N:1 관계로 설정하면 된다.
    • N : M 단방향, 양방향
      • @OneToOne 양방향 처럼 동작하지만 중간 테이블이 생성된다.
  • N : M 매핑의 문제점
    • @ManyToMany로 N:M 연관관계 설정을 하게되면 편리해 보이지만 실제로 사용하기 까다롭다.
    • 실제 설계에서는 level, license 와 같은 추가적인 데이터가 필요하다.
    • 중간 테이블이 숨겨져 있어서 생각하지 못한 SQL Query가 실행된다.
    • 두 id 를 묶어서 PK로 설정된다.

상속관계 매핑

  • 테이블 전략
    • JPA에서 엔티티 상속 구조를 데이터베이스 테이블에 매핑하는 방법
    • JPA는 엔티티의 상속 구조를 처리하기 위해 3가지의 테이블 전략을 제공
    • 각각의 전략은 데이터 저장 방식과 성능에 차이가 있으므로 프로젝트의 요구사항에 맞게 선택
    • 상속관계 매핑 구현방법
      • 조인 전략
      • 단일 테이블 전략
      • 구현 클래스
  • JPA의 테이블 전략
    • JPA는 모든 전략으로 테이블을 구현할 수 있도록 지원
      • Annotation
        • @Inheritance(strategy = InheritanceType.${전략})
        • @DiscriminatorColumn(name = "dtype")
        • @DiscriminatorValue("${값}")
      • JPA의 조인 전략에서 @DiscriminatorColumn을 선언하지 않으면 DTYPE 컬럼이 생성되지 않는다.
      • JOIN을 통해 테이블을 구분할 수 있지만, DTYPE 컬럼을 넣어주는 것이 명확
    • JOINED
      • 장점
        1. 테이블 정규화
        2. 외래 키 참조 무결성
        3. 저장공간 효율
      • 단점
        1. 조회시 JOIN을 많이 사용.
        2. 데이터 저장시 INSERT SQL 이 2번 호출.
        3. SQL Query가 복잡하여 성능이 저하.
    • SINGLE_TABLE
      • 장점
        1. JOIN을 사용하지 않음.
        2. 실행되는 SQL이 단순.
      • 단점
        1. 자식 Entity가 매핑한 컬럼은 모두 null을 허용
        2. 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있음.
        3. 상황에 따라서 조회 성능이 오히려 느려질 수 있음.
    • TABLE_PER_CLASS
      • 테이블끼리 연관짓기 힘듬
      • 사용하지 않는것을 권장.
      • 장점
        1. 자식 클래스를 명확하게 구분해서 처리.
        2. not null 제약조건 사용이 가능.
      • 단점
        1. 여러 자식 테이블을 함께 조회할 때 성능이 느림.
        2. 부모 객체 타입으로 조회할 때 모든 테이블을 조회.

Proxy

  • Entity 조회
    • em.getReference()
      • JPA의 EntityManager에서 제공하는 메서드로 특정 엔티티의 프록시 객체를 반환
      • 지연 로딩(Lazy Loading)을 활용해 데이터베이스 조회를 미루고 실제로 엔티티의 속성에 접근할 때만 데이터베이스를 조회하도록 함
    • em.find()
      • 데이터베이스를 통해 실제로 저장된 Entity 를 조회한다.
    • em.getReference()
      • 데이터베이스에 저장된 Entity가 아닌 가짜 Entity 객체를 조회
    • proxyTutor.getName()
      • 실제 값이 사용되는 시점에 SQL Query가 실행
    • proxyTutor
      • Hibernate가 만드는 Proxy 객체
  • Proxy
    • JPA에서 엔티티 객체의 지연 로딩(Lazy Loading)을 지원하기 위해 사용하는 대리 객체
    • 실제 엔티티 객체를 생성하거나 데이터베이스에서 값을 읽어오지 않고도 엔티티의 참조를 사용할 수 있음
    • 최초로 사용(실제 Entity에 접근)할 때 한 번만 초기화된다.
    • 프록시 객체를 통해 실제 Entity에 접근할 수 있다.
    • em.getReference() 호출 시 영속성 컨텍스트에 Entity가 존재하면 실제 Entity가 반환
    • 준영속 상태에서 프록시를 초기화하면 LazyInitializationException 예외가 발생한다.

지연로딩, 즉시로딩

  • Lazy Loading
    • 데이터를 실제로 사용할 때 데이터베이스에서 조회하는 방식
    • fetch 속성 사용
    • FetchType.LAZY : 지연로딩
    • 지연로딩을 사용하면 Proxy 객체를 조회한다.
    • 연관된 객체(Company)를 매번 함께 조회하는것은 낭비인 경우에 사용
  • Eager Loading
    • 엔티티를 조회할 때 연관된 데이터까지 모두 한 번에 로드하는 방식
    • fetch 속성 사용
    • FetchType.EAGER : 즉시 로딩
    • Proxy 객체를 조회하지 않고 한 번에 연관된 객체까지 조회한다.
    • 관된 객체(Company)를 매번 함께 조회하는것이 효율적인 경우에 사용
  • 즉시 로딩 주의점
    • 즉시 로딩(Eager Loading)을 사용하면 개발자가 예상하지 못한 SQL이 실행
    • JPQL에서 N+1 문제가 발생
    • 꼭 필요한 경우가 아니라면 지연 로딩을 사용

영속성 전이

  • Cascade
    • 영속성 전이(Cascade)란 JPA에서 특정 엔티티를 저장, 삭제 등의 작업을 할 때 연관된 엔티티에도 동일한 작업을 자동으로 적용하도록 설정하는 기능
    • CascadeType.ALL
  • 사용 방법과 주의점
    • 영속성 전이(Cascade)
      • 단순히 Entity를 저장, 삭제할 때 연관된 Entity에도 동일한 작업을 적용
      • 속성 종류
        1. ALL : 모두 적용
        2. PERSIST : 영속
        3. REMOVE : 삭제
        4. MERGE
        5. REFRESH
        6. DETACH
      • 단일 Entity에 완전히 종속적인 경우 생명주기가 같다면 사용
  • 고아 객체
    • JPA에서 부모 엔티티와의 연관관계가 끊어진 자식 엔티티
      • 부모 엔티티와 연관관계가 끊어진 자식 Entity를 자동으로 삭제
      • orphanRemoval = true 사용
      • 기본 값 : false
      • CascadeType.REMOVE와 비슷하게 동작
      • CascadeType.ALL과 orphanRemoval=true 를 함께 사용하는 경우 부모 Entity를 통해서 자식 Entity의 생명주기를 관리할 수 있다

JPA와 Transaction

  • 트랜잭션 전파
    • 하나의 트랜잭션이 다른 트랜잭션 내에서 어떻게 동작할지를 결정하는 규칙
    • 여러 개의 트랜잭션이 포함된 시스템에서 특정 작업이 다른 작업에 어떻게 영향을 미칠지를 정의
    • 현재 클래스의 트랜잭션과 다른 클래스의 트랜잭션을 교통정리
    • 트랜잭션이 여러 계층 또는 메서드에서 어떻게 처리될지 정의한다.(@Transactional)
    • propagation  속성을 통해 트랜잭션의 동작 방식을 제어
    • 다양한 비즈니스 요구 사항에 맞춰 복잡한 트랜잭션 흐름을 유연하게 설계할 수 있도록 돕는다.
    • 데이터 무결성과 비지니스 로직의 안정성을 보장할 수 있다.
      • 트랜잭션 전파 종류
        • propagation 속성
          1. REQUIRED(Default)
            • 기존 트랜잭션이 있다면 기존 트랜잭션을 사용
            • 기존 트랜잭션이 없다면 트랜잭션을 새로 생성
          2. REQUIRES_NEW
            • 항상 새로운 트랜잭션을 시작하고, 기존의 트랜잭션은 보류
            • 두 트랜잭션은 독립적으로 동작
          3. SUPPORTS
            • 기존 트랜잭션이 있으면 해당 트랜잭션을 사용
            • 기존 트랜잭션이 없으면 트랜잭션 없이 실행
          4. NOT_SUPPORTED
            • 기존 트랜잭션이 있어도 트랜잭션을 중단하고 트랜잭션 없이 실행
          5. MANDATORY
            • 기존 트랜잭션이 반드시 있어야 함
            • 트랜잭션이 없으면 실행하지 않고 예외를 발생
          6. NEVER
            • 트랜잭션 없이 실행되어야 함
            • 트랜잭션이 있으면 예외를 발생
          7. NESTED
            • 현재 트랜잭션 내에서 중첩 트랜잭션을 생성
            • 중첩 트랜잭션은 독립적으로 롤백할 수 있음
            • 기존 트랜잭션이 Commit되면 중첩 트랜잭션도 Commit