[Spring] JPA

쓰옹·2022년 12월 12일
0

JPA (Java Persistence API)

  • 자바 ORM(객체 관계 매핑) 기술에 대한 표준 명세
  • 쿼리 자동 생성
  • 어플리케이션 계층에서 SQL의존성 줄여 작업 단축
  • 객체지향 모델과 관계형 데이터베이스의 패러다임 불일치 해결

Spring Data JPA

  • 스프링 프레임워트에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트
  • 데이터 접근 계층을 개발할 때 구현 클래스 없이 인터페이스만 작성하면 필요한 구현은 스프링이 함
       public interface ProductRepository extends JpaRepository<Product, Long> {
       }
  • Spring Data JPA를 사용하지 않았다면
    • Entity를 관리해 줄 EntityManager를 생성하고 그걸 위해서 EntityManagerFactory도 만들어줘야함

영속성 컨텍스트

  • 엔티티를 영구 저장 하는 환경

  • 어플리케이션이 데이터베이스에서 꺼내온 데이터 객체를 보관하는 역할

  • 엔티티를 조회하거나 저장할 때 보관, 관리

  • 식별자로 엔티티 관리, 구분

  • JPA 엔티티의 상태

    • 비영속(New)
      : 영속성 컨텍스트와 관계 없는 새로운 상태. 실제 DB와 관련 없는 Java 객체
    • 영속(Managed)
      : 엔티티매니저를 통해 영속성 컨텍스트에 저장되어 관리되고 있는 상태
      - 데이터의 생성, 변경 등을 JPA가 추적하면서 필요하면 DB에 반영
    • 준영속(Detached)
      : 영속성 컨텍스트에서 관리되다가 분리된 상태
    • 삭제(Removed)
      : 영속성 컨텍스트에서 삭제된 상태

** 플러시(fluch()) - 영속성 컨텍스트의 변경 내용을 DB에 반영하는 연산

  • 수행
    • 변경 감지 → 영속성 컨텍스트의 엔티티와 스냅샷 비교 → 수정된 엔티티 수정 쿼리 생성 → 쓰기 지연 SQL 저장소 등록
      • 쓰기 지연 SQL 저장소 → DB 로 쿼리 전송
    • 영속성 컨텍스트에 엔티티를 저장하고 트랜잭션을 커밋하는 순간 DB에 반영

설계방식

  • 1차캐시

    • DB를 이용하는 작업은 상대적으로 부하와 비용이 심한 작업임 → 줄여야 할 필요가 있음
    • 영속성 컨텍스트 내부에 1차캐시를 두고 사용
      1. find(”memberB”)와 같은 로직이 있을 때 먼저 1차 캐시를 조회
      2. 있으면 해당 데이터를 반환 (DB까지 가지 않음)
      3. 없으면 그 때 실제 DB로 “SELECT * FROM….” 의 쿼리를 보냄
      4. 그리고 반환하기 전에 1차캐시에 저장하고 반환
  • 쓰기 지연 SQL 저장소

    • 트랜잭션(@Transactional)에서 변경내용을 쓰기지연 저장소에 가지고 있다가 트랜잭션이 커밋되는 순간 한번에 DB로 날림
    • DB커넥션 시간 단축
  • DirtyChecking

    • 데이터 변경을 감지해서 자동으로 수정 (DB에 반영)
    • 영속성 컨텍스트가 관리하는 엔티티를 더티체킹의 대상으로 한다
      • 비해당 대상 → 값을 변경해도 DB 변화 없음 (반영되지 않음)
        • detach 된 엔티티 (준영속)
        • DB에 반영되기 전 처음 생성된 엔티티 (비영속)
  • 데이터의 어플리케이션 단의 동일성 보장

엔티티 매핑

연관관계

관계코드선언Entity
일대다 (1:N)@OneToManyOrder (1) : Food (N)배달 주문 1개에 음식 여러개 선택 가능
다대일 (N:1)@ManyToOneOwner (N) : Restaurant(1)음식점 주인 여러명이 하나의 음식점을 소유 가능
일대일 (1:1)@OneToOneOrder (1) : Coupon (1)배달 주문 1개 주문 시, 쿠폰 1개만 할인 적용 가능
다대다 (N:N)@ManyToManyUser (N) : Restaurant(N)고객은 음식점 여러개 찜 가능
음식점은 고객 여러명에게 찜 가능
  • 단방향 연관관계

    @Entity
    @Getter
    @Setter
    public class Member {
    	@Id
    	@Column(name = "member_id")
    	private String id;
    	private String username;
    	
    	@ManyToOne
    	@JoinColumn(name="team_id")
    	private Team team; //Member 여럿이 team하나에 할당
    
    	public void setTeam(Team team) {
    		this.team = team;
    	}
    }

    @ManyToOne

    • 주요 속성; optional, fetch, cascade
      - optional
      : false로 설정하면 항상 연관된 엔티티가 있어야 생성 가능
      - fetch? cascade?

      @JoinColumn(name="team_id")

    • 외래키 매핑 시 사용

    • @Column이 가지는 필드 매핑관련 옵션 설정 + 외래키 관련 옵션

  • 양방향 연관관계

    @Getter
    @Entity
    @NoArgsConstructor
    public class Member {
    	  
    		...
    
        @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
        private List<Orders> orders = new ArrayList<>();
    
        ...
    
        }
    }
    @Getter
    @Entity
    @NoArgsConstructor
    public class Orders { //연관관계 주인
    	  
    		...
    
        @ManyToOne
        @JoinColumn(name = "member_id")
        private Member member;
    
    		...
    
        }
    }
    • 객체의 단방향 로직 2개를 묶어서 양방향처럼 보이게 함
      • 맴버객체 —have— 주문객체 주소값
      • 주문객체 —have— 멤버객체 주소값
    • 데이터베이스
      • 외래키는 연관관계의 두 테이블 중 하나에만 있으면 충분함
      • 테이블 하나를 정해 테이블의 외래키를 관리
      • 연관관계 주인 == 외래키 관리자
        • 데이터베이스 연관관계와 매핑
        • 외래키 관리(등록, 수정, 삭제)
        • 연관관계 주인에 의해 mappedby 됨
      • 연관관계의 양쪽 방향 모두에 값을 입력해주는 것이 가장 안전함
  • 프록시(Proxy)

    • 가짜 객체(대리인)
    • 연관관계의 엔티티는 비즈니스 로직에 따라 사용되지 않을 때도 있기 때문에 JPA가 성능을 최적화하기 위해 사용
    • 엔티티가 실제 사용될 때까지 데이터베이스 조회 지연
      • 즉시로딩
        • 엔티티를 조회할 때 연관된 엔티티도 함께 조회
        • @ManyToOne(fetch = FetchType.EAGER)
        • 연관관계가 많고 복잡할수록 기하급수적 비용 발생 → 가급적 지연로딩을..걸어..
      • 지연로딩
        • 연관된 엔티티를 실제 사용할 때 조회
        • 프록시 객체 사용
        • @ManyToOne(fetch = FetchType.LAZY)
      • 기본값
        • @ManyToOne, @OneToOne: 즉시 로딩(FetchType.EAGER)
        • @OneToMany, @ManyToMany: 지연 로딩(FetchType.LAZY)
  • 영속성 전이

    • 특정 엔티티를 영속상태로 만들 때 연관된 엔티티도 함께 만들 수 있음

    • JPA에서 cascade옵션을 사용하여 제공

      @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
      private List<Address> addresses;




reference
김영한, 『자바 ORM 표준 JPA 프로그래밍』

profile
기록하자기록해!

0개의 댓글