JPA 단 방향(연관 관계)

2023. 6. 27. 17:27·Spring Boot

Post : 게시글

Reply : 댓 글

 

post가 주인이지만 reply안에 있는 private Post post; 로 접근하는 게 좋다.

 

일 대 다

1 > N

post 테이블에

 

@OnetoMany

@JoinColum(name = "POST_ID")

조인 컬럼 안 쓰면 하나의 테이블이 더 생긴다,

private List<Reply> replies = new ArrayList <>();

reply를 칼럼으로 인식하지 말고 연관 관계로 인식해라

@OnetoMany 쓸 때는 조인 칼럼도 같이 써서 fk의 이름도 정해주는 게 좋다.

이렇게 일대다로 연결을 해봤다.

 

디비에서 조회

SELECT * FROM POST;

SELECT * FROM REPLY;

 

Post에 Reply Id 가 있는 게 아니라

Reply에 Post Id 가 있는 것임 

그러면 접근할 때 Repyl에서 Post로 접근하는 게 RDB에서도 맞는 방향이다.(다 대 일)

 

지금은 일 대 다 이기 때문에

단위 테스트를 통해 일 대 다의 불편함 알아보기

 

post를 등록하기 전  포스트 안에 있는 리플라이를 등록하면서 같이 persist를 하면 좋겠지만 그렇게 안된다.

영속 상태가 되어 야기 때문에 Reply부터 등록을 해줘야 한다. 그래야 감지를 한다. 

r1.setContent("내용");

r2.setContent("내용");

 

rdao.save(r1);

rdao.save(r2);

 

post.ser title("제목");

post.set content("내용");

postdao.save(post);

 

디비에서 확인해 보면 post는 문제가 없는데

reply애서 post Id에 정보가 없다.

그래서 중간에 Post에게 reply 정보를 주기 위해

 

post.getReplies(). add(r1);

post.getReplies(). add(r2);

를 해줘서 알려준다.

 

전과는 다르게 update 쿼리가 나간다

이제 정확하게 post Id가 된다.

 

생각이 든다. 이렇게 reply에게 어떤 포스트인지 알려줘야 하나 귀찮게

그냥 처음부터 알고 있으면 업데이트 쿼리도 안 써도 되지 않을까.

 

그래서 이제는 일대다가 아닌 다대일로 해보려고 한다,

이제 reply에 post를 만들어준다. (기존 post에 LIST REPLY 주석)

 

@ManyToOne

@JoinColum

private Post post

근데 여기서 다대일로 조인칼럼을 post Id를 해주면 전에랑 관계 구조 자체는 비슷할 거다.

 

다시 단위 테스트로 간다.

이제는 reply를 만들 때마다 포스트를 넣어줘야 한다.

 

post.setpostTitle("제목");

post.setpostContent("내용");

poDao.save(post);

r1.set("");

r1.setPost(post);

이렇게 reply에게 너는 어떤 Post의 reply라고 지정을 해준다.

이렇게 게시글을 작성하고 댓글을 작성할 때 게시글의 정보를 넘겨주고

댓글을 저장하면 게시글의 정보를 들고 저장이 되지 않을까

 

쿼리를 보면

update쿼리가 없다 덜 나갔다. 

이처럼 다대일로 하는 게 더 편하다 쿼리도 덜 나간다.

 

 

다시 일 대 다로 돌아오자

 

조회를 해보자

postDao.findById(1L). map(Post::toString). ifpresent(log::info);

이때 쿼리를 보면 post selecte 이되고선 reply에 대한 모든 것이 조회가 된다 .

연관관계라서. 조회할 떄 연관된 댓글도 들고 와줘서 편하다.

지금은 괜찮다. 근데 테이블이 많아질 때 나는 게시글만 조회하고 싶을 때 이처럼 게시글에 연관된

모든 테이블의 칼럼이 조회가 될 거다 불필요한 쿼리들,

 

그래서 이런 거를 설정을 해주면 된다. 그러면 Post를 조회해도 Post만 조회되고, Post에 reply를

수정하거나 다른 작업을 하려고 할 때 그때 reply가 select 쿼리가 나가게 된다.

유동적으로 할 수 있음.

@OneToMany 에 fetch라는 설정이 있다. default가 Lazy이다.

Lazy는 게으르다. 뭐든 쿼리를 날려주지 않는 친구다. 사용할 때 날려준다.

그럼 위에서 default가 Lazy인데 왜 모든 쿼리가 나갔을까 우린 toString을 사용했기 때문.

toString에 getReplies가 있기 때문에 모든 쿼리가 나간 것이다.

다시 toString을 빼면 post에 관한 쿼리만 나가게 된다,.

postDao.findById(1L). ifPresent(post -> log.info(post.getPostCon())));

Lazy반대는 Eager라는 게 있다. 이것은 연결된 객체에 관한 모든 쿼리를 다 날린다.

 

이제 다대일 방식으로 조회해 보자 여기서 리플라이를 조회했을 때 과연 해당 게시글까지 정보를 받아올 수 

있을지 의문이다.

replyDAO.finbyId(2L). ifPresent(eply -> log.info(rply.getRplyConten()));

다대일은 manytoOne이다 이는 디폴트가 eager라서 쿼리가 join이 돼서 나왔다.

lazy로 바꿔서 다시 조회해 보면 댓글에 관한 내용만 나오게 된다.

쿼리를 내가 날리는 게 아니라 JPA가 해주기 때문에 성능적인 부분을 생각을 안 할 수가 없다.

 

다시 일 대다로 돌아온다

전체 조회를 해보자

log.info(postDao.findAll(). stream(). map.(Post::getTitel). forEach(log::info);

@@~~~~61번째 포스트를 통해서 reply 조회해 보기

 

수정을 해보자

final Optional found = postDAo.findById(1L);

if(sadasd)

@! 3!#@!@

@#@32

 

이제 다대일로 하자

댓글로 게시글을 수정해 보기

replyDao.findBy(2L). ifpresent(reply -> reply.getPost(). setPostTitle("PostupdateTitle"));

그래프 알고리즘이랑 유사함

여기까지가 업데이트

 

마지막 삭제

게시글부터 삭제해 보자

현 관계 : reply 안에 Post 객체가 있는 @ManyToOne 관계이다.

이때 리플라이로 포스트를 가져와야 영속 상태가 돼 삭제를 할 수 있다.

repltDao.findById(2L). ifPresent(rp -> postDao.delete(rp.getPost())));

(댓글로 게시글 삭제해 보기 가능할까?)

오류 내용 

select 쿼리는 잘 나갔는데 delete쿼리가 나가면서 오류 발생

violated : child record found(다른 자식이 참조 중이다) 쿼리에서의 cascade를 해주는 이유

 

이제 반대 방향 일대 다로(@OneToMany)

게시글하나를 가져와 해당 게시글의 댓글을 전부 삭제해보려 한다.

postDAO.findById(1L). ifPresent(po -> po.getRplies(). forEach(replyDAO::delete));

성공

부모를 삭제하면 참조 중인 자식을 다 날려버리는 on delete cascade JPA에도 있다고 한다.

시험해 보기 위해서

다대일로 

게시글에 댓글을 추가한다.

삭제 테스트

postDAO.findById(1L). ifPresent(postDAO:delete); 게시글을 지웠을 때 해당 댓글들이 다 삭제가 될까?

역시나 오류 자식에서 참조 중인 애들이 있다고 온다 이걸 가능하게 해 보자

Reply에서 

@ManyToOne(fetch ~~,CasecadeType = remove)

이것은 정확이 표현하면 영속 상태를 전이하는 것이다

내가 삭제되면 나랑 관련된 애들을 모두 삭제한다.

repltDao.findById(2L). ifPresent(rp -> postDao.delete(rp.getPost())));

다 오류 난다.

다대일 쪽에서는 케스케드리무블는 어울리지 않는다.

일대다 쪽으로 케스케드 리무브를 써본다

이제 게시글이 삭제가 되면 참조 중인 자식인 댓글이 함께 삭제되는지 테스트해 보자

postDAO.findById(1L). ifPresent(postDAO:delete);

성공 참조 중인 댓글도 모두 삭제가 됐다.

이때 쿼리를 잘 보면 그냥 selcte 다음 deletye가 아니라 조회를 하고 fk값을 null로 바꿔주고 delete가 실행된다.,

 

추가적으로 cascade 외에 persist도 있다.

 

처음 에는 insert를 미리 해주고 insert 된 거를 넣어줬다면

이제는 set메서드 변화감지만 해주고 Post를 등록만 하면 연관된 setReply해준 애들 까지도 같이 persist가 된다.

 

'Spring Boot' 카테고리의 다른 글

JPA Project 근황  (1) 2023.08.25
Get, Post, Redirect  (1) 2023.05.02
타임리프(Timeleaf)  (2) 2023.05.01
MVC 2  (1) 2023.05.01
Spring 의존성 주입  (0) 2023.04.30
'Spring Boot' 카테고리의 다른 글
  • JPA Project 근황
  • Get, Post, Redirect
  • 타임리프(Timeleaf)
  • MVC 2
JAVALA
JAVALA
워니‘s Diary
  • JAVALA
    정신줄 JAVA라
    JAVALA
  • 전체
    오늘
    어제
    • 분류 전체보기 (87)
      • Codding_Test (11)
        • BaekJoon (7)
        • Programmers (3)
      • Algorithm (11)
      • Daily (4)
        • memoir (4)
      • TroubleShooting (8)
        • InteliJ (1)
        • Server (1)
        • Infra (0)
        • DB (0)
      • Computer Science (1)
      • JAVA (8)
      • Javascript (0)
      • Spring Boot (7)
      • API (2)
      • Server (0)
      • DB (3)
        • ORACLE (1)
      • Infra (2)
      • Refactoring (1)
      • Plugin (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    개발자 비전공자
    프로그래머스
    자바 알고리즘
    백준
    스프링부트
    springboot
    자바 스프링부트
    개발자
    프론트엔드 개발자
    트리 자료구조
    코딩테스트
    개발자 국비
    자바 메소드
    제로베이스
    자바
    spring boot
    백엔드 개발자
    개발자 부트캠프
    자바 클래스
    자바 스프링
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
JAVALA
JPA 단 방향(연관 관계)
상단으로

티스토리툴바