단방향 연관관계
persist하면 pk값 생성됨.
객체를 DB에 맞춰 셋팅하면 문제 생김 :
MEMEBER 첫번재 데이터_ID가 2인 이유: 공용 sequence를 사용해서 TEAM의 첫번째 데이터 _ID가 1이기 때문에...!
=> 따로따로 ID를 1부터 사용하려면 식별자 맵핑해주면 됨.
------------
객체지향 : 객체를 참조해서, 객체 대상으로 쿼리 (JPQL)
DB : 외래키를 가지고, 테이블 대상으로 쿼리 (SQL)
MEMBER는 객체인 TEAM을 가지고 있지만 DB는 TEAM의 키를 가지고 있음.
MEMBER의 팀을 b팀으로 바꾸면 jpa는 객체가 바뀌는데 DB는 키값만 바뀜
----------
persist 하고 바로 find 하면 1차캐시에서 들고오기 때문에 select 쿼리 안 날라감
DB에서 가져오고 싶으면 em.persist(); => em.flush(); DB와 싱크맞추기 => em.clear(); 영속성컨텍스트 초기화
양방향 연관관계와 연관관계의 주인 2 - 주의점, 정리
member와 team 중 (1:n일 때 n쪽이 주인) member가 연관관계의 주인.
연관관계 설정할 때 주인에게는 값을 꼭 넣어줘야한다.
jpa가 mapped by한건(주인 아닌얘) update, insert할 때 안 봄. 따라서 team의 members는 읽기 전용임
member.setTeam(team); 꼭 해야됨.
team. getMembers().add(member); 이건 해도 안해도 상관x but 얘도 하는게 좋음
순수 자바 코드로 테스트 할 경우를 생각했을 때(진짜 객체 지향으로 생각하면)는 양쪽에 다 값을 넣어줘야 양방향 연관관계가 유지됨.
그리고 양쪽에 다 값을 넣어줘야 flush, clear 안했을때도 persist만 했을때 1차 캐시에서 가져와 뒤에서 변수 사용가능함.
team 객체만 만들면 join이 아직 안 된 team 객체만 1차캐시에 있음. team의 멤버를 물으면 select 쿼리가 날라가지 않음. (1차 캐시에는 join이 안되어 멤버가 채워져있지 않기 때문)
---------------
연관관계 편의 메소드를 생성하자.
연관관계 편의메소드란?
team.getMermbers().add(member)를 메인에서 따로 해주지 말고
Member entity에 가서 setTeam 할때 team.getMermbers().add(this)를 해주기
그리고 setTeam 이름은 changeTeam으로 이름 바꿔주기
*자바 메인에는 member.changeTeam(team)코드가 된다.
어쨌든 양쪽에 값 다 셋팅해줘야함 -> 연관관계 편의 메소드는 1이나 n이나 어디에나 해도 됨.
------------
!조심! !조심! !조심!
Member의 toString은 Team의 toString을 부르고 Team의 toString은 Member의 toString을 부르며 서로 계속 호출함. 무한루프에 걸리지 않게 둘 중 하나는 빼고 써라
controller에서는 entity를 dto로 변환해서 반환해라
설계는 단방향맵핑으로 해두고 개발할때 반대방향으로 조회기능을 추가시키기(개발할때 정말 필요하면 양방향으로 만들기)
실전 예제 2 - 연관관계 매핑 시작
객체 지향적 x : member의 id 찾는 쿼리 날리고 find (Team.class,member.id)쿼리 한번더 날림
객체 지향적 o: member.getTeam() 쿼리 한방에 team 찾음
-----------
핵심! 단반향을 먼저 하고 비지니스상 양방향이 더 좋으면 개발하다 바꾸자
일대다 [1:N] (거의 사용 x)
1:다는 옆테이블에 update해야하기 때문에 update 쿼리가 한번 더 날아감.
@joinColumn 꼭 사용해야함(안 그러면 중간테이블 만들어짐)
일대다인데 읽기 전용으로 양방향을 쓰고 싶을때(다대일과 똑같이 하되, 조인컬럼 안에 어쩌고 부분이 추가)
@ManyToOne
@JoinColumn(name = "", 어쩌고~~~~)써라
이렇게 하면 값은 다 들어가지는데 최종적으로 읽기전용으로 DB에 insert, update가 안됨
--------------
핵심! 걍 다대일 써라~~~~~~~~
일대일 [1:1]
Member 객체에 locker필드가 있으며 Locker에는 member필드가 없다.
따라서 MEMBER가 주 테이블, LOCKER가 대상 테이블
주테이블에 외래 키 단방향
MEMBER에 LOCKER_ID가 있으면 Member객체에 @joinColumn 사용
주 테이블 아닌 곳에 @OneToOne(mappedBy="")
대상 테이블에 외래 키가 있는 단방향
아예 지원이 안됨~~~~ 이런건 없어요~~
대상 테이블에 외래 키가 있는 양방향
걍 Locker를 주인으로 두고 LOCKER의 MEMBER_ID와 연결시킴. 걍 주인을 Locker로 옮긴 주 테이블에 외래 키 양방향임....
DB 어디에 외래키를 둬야하나..?
비지니스 측면에서 나중에 MEMBER가 LOCKER를 여러개 사용할 수 있을 수 있다 생각하면 LOCKER에 MEMBER_ID가 있는게 나음 (UNIQUE 제약조건만 없애면 되기 때문)
BUT 반대는 코드 수정이 많이 필요함.
따라서 비지니스 측면을 생각해 미래를 대충 생각하고 선택
개발자입장에서는 멤버에 locker_id가 있는게 좋음. MEMBER를 조회할 때가 더 많음. LOCKER가 있는 사람과 없는 사람에 따라 뭐 나눠야하면 조인없이 쿼리 하나로 LOCKER여부(NULL인지) 알 수 있음!
만약 LOCKER에 MEMBER_ID가 있는데 주로 Member를 통해 locker에 access하면 양방향으로 만들어야함.
다대다 [N:M]
핵심! 다대다는 중간테이블을 엔티티로 승격해라!(다대다 쓰지말고 1:다, 다:1로 나눠라)
!주의! 웬만하면 pk는 데이터와 상관없이 generateValue로 하길..!
실전 예제 3 - 다양한 연관관계 매핑
다대다는 @JoinTable(name="",joinColumns = @JoinColumn(name=""),inverseJoinColumns = @JoinColumn(name ="")) 내가 조인하는건 이거고 반대편애가 조인하는건 얘야. 중간테이블이 있다 치고 만들기
상속관계 매핑
기본적으로 단일테이블전략으로 생성되는데 Item에 @Inheritance(전략 어쩌고 join)을 해주면 조인전략으로 테이블 생성됨.
@DiscriminatorValue을 부모에 쓰면 DTYPE이 저절로 생김 (DTYPE은 자식 엔티티의 이름이 들어감)
@DiscriminatorValue("")을 자식에 쓰면 부모의 DTYPE필드에 ("")명이 들어감
@DiscriminatorValue
Item
-----
@DiscriminatorValue("M")
Movie면
---------DB에는
ITEM MOVIE
DTYPE | Id Id
M | 1 1 id는 둘이 같음
----------------------------
싱글테이블은 @DiscriminatorValue안 넣어도 DTYPE 생김
전략 table_per_class
ITEM을 없애고 ALBUM, MOVIE 등에 걍 ITEM 속성들을 각각 넣어 중복돼도 상관없이 .
전략 table_per_class하고 Item을 abstract로 만들면 ITEM안 만들어지고 MOVIE에 name, price등이 들어감.
이때는 @DiscriminatorColumn은 DTYPE 안 쓰니까 필요없어서 써줘도 효과 X
BUT movie의 id만 알면 모든 테이블(album, book)도 다 뒤져야해서 쿼리가 복잡
나머지 전략은 싱글테이블 전략일경우 id알면 한 테이블만 뒤지면 되고 조인전략인 경우 id알고 Dtype알면 바로 알 수 있다.
!주의! 구현클래스마다 테이블 전략은 쓰지 마라~~~~
핵심!
비지니스적으로 중요하고 복잡함, 데이터가 많으면 조인
데이터도 얼마없고 단순하면 싱글테이블
보통은 조인 많이 씀
Mapped Superclass - 매핑 정보 상속
DB는 완전히 개별적인데 객체에는 같은 속성을 부모로 만들어서 속성만 받아서 쓰고싶을 때! (등록일, 수정일에 유용)
핵심! 상속은 절대 아님
부모는 @MappedSuperclass해주고 @Entity 하지말기. 자식은 extends 하고 상속받기
------------------ 구현클래스마다 테이블전략와 차이
구현클래스마다 테이블전략은 movie의 id로 검색하려면 album, book도 다 union해서 검색해야되는데 얘는 걍 ㄹㅇ 지 혼자 독립적인 애라 바로 검색가능
-----------------
super에 @Entity가 있으면 상속관계맵핑(윗 내용)이고
@MappedSuperclass가 있으면 속성만 상속할때 씀
실전 예제 4 - 상속관계 매핑
item만 따로 만들 일이 있냐 없냐로 abstract의 여부 결정
album, book, movie는 같은 Item묶음이니까 entity를 써주고 날짜를 쓸 때 delivery, order, item은 같은 묶음이 아니니까 @MappedSuperClass로 속성만 내려 사용
'Spring boot' 카테고리의 다른 글
[spring boot] test시 (H2 DB의) 메모리모드 사용 (0) | 2021.11.14 |
---|---|
[spring boot] 3차 정리 (프록시, 즉시 로딩, 지연 로딩) (0) | 2021.11.04 |
[spring boot] 1차 정리(jpa 시작, 영속성관리, 엔티티 매핑) (0) | 2021.10.28 |
[spring boot] flush란? persist, flush, commit 비교 (0) | 2021.10.11 |
[spring boot] 영속성 컨텍스트 (0) | 2021.10.10 |