JPA 관계, 방향 설정해보기
스프링 목록
- Spring(1) - 백엔드 초기설정
- Spring(2) -스프링 Client 파일 업로드(1)
- Spring(3) -스프링 Client 파일 업로드(2)
- Spring(4) - 백엔드 RESTFULL 로 바꾸기
- Spring(5) - 게시판 페이징 기능 추가하기
- Spring(6) - 검색 기능 추가
- Spring(7) - 프론트 ContextPath 동적 설정
스프링 부트 목록
- Spring Boot(1) - 스프링 부트 초기설정
- Spring Boot(2) - JPA 사용해 보기
- Spring Boot(3) - JPA 방향설정, 관계설정
- Spring Boot(4) - JPA 심화
- Spring Boot(5) - JPA 일대일 실습
생각보다 까다로운 관계 설정과 방향설정
관계 설정
(@ManyToOne, @ManyToMany, @OneToMany)
- 게시글은 댓글을 가지고있음, 게시글 하나에 댓글이 여러개 달릴수 있음
게시글(One) To 댓글(Many)- 댓글 입장에선 여러개의 댓글은 하나의 게시글에 달려있음
댓글(Many) To 게시글(One)
방향설정
- 방향 설정은 한쪽이 어느쪽을 자주 포함하는지에 따라 설계
ex) 쇼핑몰상품
과결제내역
테이블이 존재
결제내역
에서 어떤 상품을 샀는지 조회하는 경우는많음
반대로상품
을 조회하면서 결제내역을 보는 경우는 적음
결제내역 -> 상품 (단방향)
반대의 경우를 조회하고 싶을때는 양방향으로 만들지말고 Fetch Join 이용
단방향
설계하기가 생각보다 까다로움, 그러나 설계 후에는 코드관리 용이
1. @Many To One(단방향)
- 구현 상대적으로 쉬움
@Entity
@Table
public 결제내역{
//결제에 관한 멤버변수들 .. 날짜, 갯수 등등
@Id
Long 결제번호;
int 갯수..
Date 결제날짜 등등..
//결제내역이 [Mnay]인 상황
// 해당 어노테이션과, One의 자료형만 적어주면 끝
@ManyToOne
Product product //결제한 상품
}
결제 내역에서 상품을 보는경우는 많음(단방향)
가끔씩,
상품
을 이용해 결제내역 정보를 보고싶으면
(해당 스웨터[상품]의 총 판매 수 )
Product에 @OneToMany 사용하지 말고(양방향
으로 바꾸지 말고!)
Fethch Join
으로 사용
- (JPA가 아니였으면 sql사용시 아우터 조인으로 간단히 처리할수 있는 상황)
2 .@One To Many(단방향)
- 생각보다 까다로움
- repository 만들때 One 위주로 만들것 (작업단위, 업(JOb) 위주. TDD)
cascade
로 영속성 관리, 영속성 전이 까지 고려해야함- 영속성 전이 할거면
Lazy Loading
문제 꼭 고려해야함 아래설명@JoinColumn
쓸지 안쓸지 잘 고려해야함
@Entity
@Table
public 게시판{
//게시판에 관한 멤버변수들 ..
@Id
private int 게시판_번호;
private String 글제목;
private String 작성자; //등등..
//게시판이 [One]인 상황
//Many를 리스트 형식으로 가지고 있음
@OneToMany(
//CascadeType 사용시, 해당 객체 변경시 자동으로 저장해줌(영속성 전이)
cascade= CascadeType.ALL,
//영속성 전이 사용시 Lazy Loaind 문제때문에 fetch나 다른 처리 해줘야함
fetch=FetchType.EAGER )
//조인 컬럼 사용할 경우 DB에 BoardFile의 (PK키)를 FK로 참조
@JoinColumn(name="file_no")
List<BoardFile> files;
영속성 전파 할경우
Lazy Loading
문제 해결 꼭해야함
- 해결법 예시 : fetch로 EAGER 주거나, @Transactional 어노테이션 주기
- 문제는 EAGER 사용시 N+1 문제 발생
@JoinColumn 사용 안하면 JPA가 자동으로
브릿지 테이블
생성해줌
양방향
초기 설계가 단방향에 비해 빠름, 그러나 코드가 복잡해짐
3. @ManyToOne, @OneToMany (양방향)
a)One (의 시점)
mappedBy
써줘야함 ( One (부모) 삭제 시 Many(자식) 문제가됨 )
SELECT 할시에Lazy Loding
때문에 에러 발생할 수 있음 (영속성 전파 관련문제)
@Entity(name = "order_info")
@Table(name = "jpaorder_info")
@SequenceGenerator(name = "jpaorder_seq_generator",
sequenceName = "JPAORDER_SEQ",
initialValue = 1,
allocationSize = 1)//1씩증가
public class OderInfo {
@Id
@GeneratedValue( strategy = GenerationType.SEQUENCE,
generator = "jpaorder_seq_generator"
)
private int order_no;
@CreationTimestamp
private Date order_dt;
// 이 부분은 OrderInfo가 [One]인 상황
//[Many]
@OneToMany(cascade = CascadeType.ALL,
//자식들도 인서트 되게할려면all(영속성 전이)
fetch = FetchType.EAGER,
mappedBy = "order_info")
private List<OderLine> lines;
//추가 예시
// 원래의 예제 코드라면 One의 입장에서만 보여줬겟지만
// 실제의 코드는 이런식으로 Many이면서, One일수도 있음
// 이 부분은 OrderInfo가 [Many]인 상황
//[One]
@ManyToOne
@JoinColumn(name = "order_id") //이거안쓰면 ddl오토 시 이름자동으로 order_)c
//One
private Customer order_c;
b) Many (의 시점)
@ManyToOne 어노테이션만 적을시
브릿지 테이블
생성됨(ddl-auto 설정시)
@JoinColumn(FK를 위한 어노테이션) 사용하면One의 @Id가져옴(브릿지 테이블 안생김)
아래 예시는 @Id가 2개인 복합키인 예시!Serializable
구현 해야함
@Entity(name = "orderline")
@Table(name= "jpaorder_line")
public class OderLine implements Serializable{
//복합키로 아이디 쓸때 시리얼라이저블 인터페이스 구현
//객체직렬화를 가능하게 구현한다.
// 이 부분은 OrderLine가 [Many]인 상황
//[One]
@Id
@ManyToOne
@JoinColumn(name = "order_no" )
private OderInfo order_info;
// 이 부분은 OrderLine가 [Many]인 상황
//[One]
@Id
@ManyToOne
@JoinColumn(name = "order_prod_no")
private Pruduct order_p;
Lazy Loding 문제 해결법
@Transactional
사용- @OneToMany에
fetch=FetchType.EAGER
사용(N+1문제 유의)
성능에 영향을 줌으로 신중히 사용할 것
N+1문제 발생 설명(링크)
@Transactional 쓰면 오류 안나는 이유
- PC는 트랜잭션과 관련있어서 트랜잭션 시작시 PC할당되고, 완료시 사라짐
@Transactional 없는
경우
- 레이지 로딩이
SELECT
먼저 읽어옴
글번호, 글제목 가져옴 ,댓글
은 아직 안가져옴(조인이라)- SELECT 만하고 JOIN구문을 안하고
pc
를 닫아버림- o.getReplies 로 댓글가져오고싶어도 pc가 이미 닫혀서
오류
@Transactional 사용시
- 레이지 로딩이
SELECT
먼저 읽어옴
글번호, 글제목 가져옴 ,댓글
은 아직 안가져옴(조인이라)@Transactional
어노테이션이 로직 끝나기전까지 PC닫는거 막아 줌- o.getReplies 구문 사용할 기회가 남아있음 (pc가 열려있음)
- o.getReplies select하고 종료