"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."
www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그
www.inflearn.com
양방향 연관관계와 연관관계의 주인을 정하는 데 있어 주의할 점?
- 연관관계의 주인 클래스 객체에 값을 입력하지 않고, 역방향(주인이 아닌 클래스의 객체) 만 연관관계가 설정되어 있으면 안된다.(외래 키 값으로 null 값을 반환받게 된다.)
* 객체 지향적으로 보았을때, 양방향 관계의 경우 그냥 양쪽에 모두 값을 넣어주면 된다.
아래는 연관관계의 주인 클래스 객체에 값을 입력하지 않았을 경우의 예시이다.
- JpaMain.java
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
// 역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
/* 결과로 Member 테이블에 Team 데이터에 대한 데이터가 제대로 insert 되지 않아,
멤버 데이터의 Team 값이 null 로 표시된다. */
em.persist(member);
- 아래는 양방향 연관관계 에서 양쪽 모두에 값을 넣어준 경우의 예시이다.
- JpaMain.java
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
team.getMembers().add(member);
// getMembers 를 통해 1차 캐시에서 데이터를 찾아온 후 값을 삽입해준다.
여기서 사실 한번 주인으로 지정된 도메인 클래스에서 값을 넣어주면, 역방향으로 값을 넣어주지 않아도 find 메소드를 통해 데이터를 얻기를 원하는 Team 데이터를 찾아온 다음(첫번째 select query 전달) 해당 팀에서 찾고자 하는 멤버 데이터를 List 타입으로 찾아옴 으로서(두번째 select query 전달) 데이터를 가져올 수 있다.
- JpaMain.java
Team findTeam = em.find(Team.class, team.getId()); // 첫번째 select
List<Member> members = findTeam.getMembers(); // 두번째 select
그런데 역방향으로 값을 넣어주지 않으면 객체지향 스럽지 않아 보이는 것도 있지만, 여기서 2가지 문제가 발생하게 된다.
- flush(), clear() 를 통해 현재 쓰기 지연 SQL 저장소에 쌓여있는 SQL 쿼리들을 데이터베이스에 전달해주면 문제가 없으나, 두 메소드를 실행시키지 않으면 어떻게 될까?
-> find 메소드로 team 데이터를 찾을 때 1차 캐시에서 데이터를 찾아오게 된다.(1차 캐시에 있는 변경 데이터들이 아직 전달되지 않은 상태이기 때문) 즉, getMembers 를 통해 List 타입 데이터에 값을 삽입시켜도 컬렉션이 아직 비어있는 상태이기 때문에 해당 데이터에 어떤 값도 들어가지 않게 된다.
여기서 좀 더 자세하게 알아보자
1차 캐시에서 데이터를 찾아왔는데, 왜 컬렉션이 비어있는 상태일까?
위에서 얘기한 1차 캐시에 있는 변경 데이터들이 아직 전달되지 않은 상태임을 구체적으로 설명해보자.
- 처음 team 데이터가 만들어지고 persist 메소드를 통해 영속성 컨텍스트에 entity 가 올라갈때 데이터가 아무것도 들어가 와 있지 않은 상태이다.(비어있는 상태)
- 이 team 데이터에 값이 들어오려면 주인 도메인 클래스에서 값을 삽입해 준 후 트랜잭션 커밋을 통해 데이터베이스에 insert query 가 전달되어야 한다.
- 그런데 여기서 아무 데이터도 삽입되어 있지 않은 상태인 1차 캐시의 데이터를 find 로 찾아오면 당연히 getMembers 를 통해 List 타입의 데이터에 값을 삽입해주려고 해도, 아무것도 들어있지 않은 상태이기 때문에 어떤 값도 찾아올 수 없는 것이다.
이쯤에서 EntityManager 클래스의 flush 메소드에 대해 다시 한번 복습해보자.
해당 정보와 관련된 글은 아래 링크를 찾아가면 된다.
evan-development.tistory.com/14
플러시(flush) 에 대하여...
"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다." 이번엔 앞서 작성한 영속성 컨텍스트 포스팅에서 언급했던 플러시(flush) 에 대해서 알아보자. "플러시(flush)" 란 영속성 컨��
evan-development.tistory.com
- 위의 링크를 타고 가면 알 수 있듯이 보통 flush 가 발생하는 경우는 변경 감지(Dirty Checking) 를 통해 entity 에 수정된 것이 있음을 감지하면, 수정된 entity 에 대한 update 또는 insert 쿼리가 쓰기 지연 SQL 저장소에 전송 된 후 데이터베이스 트랜잭션 커밋이 발생하면 되는 시점이다.
- 이후 쓰기 지연 SQL 저장소에 있던 쿼리들을 데이터베이스로 전달함으로서 데이터의 변경이 발생하게 된다.
- 그런데 여기서 영속성 컨텍스트에 올라온 데이터가 flush 를 통해 값이 변경되거나(update) 삽입(insert) 되지 않은 상태인 채로 해당 데이터를 1차 캐시에서 찾아 사용하려고 하면, 아직 변경사항이 적용되지 않은 상태이기 때문에 변경된 데이터를 제대로 사용할 수 없게 되는 것이다.
- 만약 flush 를 중간에 강제로 발생시켜도 되는 상황이라면 상관없겠지만, 개발을 하다 보면 아직 flush 를 발생시키면 안되는 상황에 놓여있는 상태에서 1차캐시에서 entity 를 찾아와 사용해야 하는 경우가 있을 것이다.
- 그렇기 때문에 역방향, 즉 주인이 아닌 도메인 클래스에서 값을 add 시키는 작업이 필요한 것이다.
(flush 를 발생시키지 않아도 원하는 데이터를 찾아올 수 있게 된다.)
- 물론 여기서 역방향 삽입을 제대로 사용하려면 주인 도메인 클래스 객체에서도 값을 삽입시켜 줘야 한다는 것을 잊어서는 안될 것이다.(외래 키 매핑 자체가 JoinColumn 어노테이션을 사용하는 주인 도메인 클래스에서만 가능하기에 해당 클래스의 객체에 값을 넣어주는 작업은 필수로 요구된다.)
* 결국 결론적으로 생각해보자면 역방향 삽입은 데이터를 데이터베이스에 쿼리를 전달하는 것이 아닌, 1차 캐시에서 데이터를 가져오기 위하여 이용하는 것으로 생각해 볼 수 있을 것이다.(성능 향상에 어느정도 도움이 된다.)
다음 번 글에서는 양방향 연관관계에 있어 역방향 삽입을 이용하는 또 하나의 경우와, 양방향 매핑시 추가적으로 주의할 점에 대해서 알아보자.
'JPA' 카테고리의 다른 글
다양한 연관관계 매핑 - 1 (0) | 2020.10.03 |
---|---|
연관관계 매핑 기초 - 4 (0) | 2020.09.28 |
연관관계 매핑 기초 - 2 (0) | 2020.09.28 |
연관관계 매핑 기초 - 1 (0) | 2020.09.27 |
실전 예제 1 - 요구사항 분석과 기본 매핑(2) (0) | 2020.09.22 |