작성
·
408
2
안녕하세요 JPA 활용 1편을보고 넘어왔습니다..
1)질문
그렇나 현재 아직 이해못한점이
연관관계 편의메서드를 사용하면 어느면서에서
이점이 발생하는지 잘모르겠습니다..
양방향관계시 연관관계메서드 에서
public void setTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
team.getMembers().add(this);
이부분이 team 엔티티에서도 Member의 값을 가질수있도록 하는것으로 보여집니다만
team.getMembers().add(this); 이부분이없어도
Team team = em.find(Team.class, teamA.getId());
System.out.println("연관관계"+team.getMembers());
team.getMembers() 를해도 값이 잘 보여집니다..
어느면에서 편의가 발생하는지 감이잘 안잡힙니다 ㅠ..
2)질문
일대 다 관계에서 페치조인 쿼리로 페이징을하면 데이터 뻥튀기 때문에 위험하다고 하셨습니다.
그래서 직접 확인을해보고있는데욥
Team teamA = new Team();
teamA.setName("팀A");
em.persist(teamA);
Member member1 = new Member();
member1.setUsername("회원1");
member1.setAge(10);
member1.setTeam(teamA);
em.persist(member1);
Member member7 = new Member();
member7.setUsername("회원7");
member7.setAge(10);
member7.setTeam(teamA);
em.persist(member7);
String query = "select t from Team t join fetch t.members";
List<Team> result = em.createQuery(query,Team.class)
.setFirstResult(0)
.setMaxResults(1)
.getResultList();
for (Team team : result) {
System.out.println("팀이름 = " + team.getName());
for (Member member : team.getMembers()){
System.out.println("------------> member = " + member);
}
}
결과
딱이렇게 나왔는데 이것이 뻥튀기가 된결과인가요?
어느부분에서 위험한것인지 잘 모르겠습니다 ..
(제생각으로는 0번인덱스 페이지에 팀의값 1개가 잘 출력됫다고 생각되거든요 아니라면 팀에 맴버의 값을 1개만 출력해야하는데 두개가 출력이되어서 문제인건가요?)
답변 2
3
2. 일대다에서 fetch join 을 하면 데이터가 뻥튀기되는 이유는 fetch join 때문이 아니고 SQL 문 실행 자체가 그렇게 되기 때문입니다.
위의 fetch join 는 결국 inner join SQL문을 실행시키고 다음과 같은 결과물을 뽑습니다.
(TeamA의 ID는 1, member의 id는 각각 1, 2라 가정)
TEAM_ID, MEMBER_ID
1, 1
1, 2
즉 team은 하나밖에 없는데 멤버수만큼 row수가 뻥튀기되서 결과물이 나오게 됩니다.
일반적인 페이징 방식으로 첫 번째 레코드만 뽑는다고 하면, 위의 결과물에 첫번째 레코드만 반환을 하게 되는데 그렇게 되면 teamA에 멤버1밖에 딸려나오지 않습니다. 사용자의 의도와는 다른 결과물이 나오게 되지요. 따라서 DB단계에서의 최적화를 기대할 수 없기 때문에 DB에서 모든 데이터를 다 조회하고 메모리에서 추려내는 수밖에 없게 됩니다.
위에서는 멤버가 둘 밖에 없어서 괜찮았지만 멤버가 1000만명이었다면, 첫 1개만 뽑고싶어도 DB에서는 1000만개의 레코드를 전부 조회해서 가져온다음에 메모리 상에서 첫 1개만 추려내게 되기 때문에 의도와는 다르게 굉장히 무거운 작업이 되어버립니다.
결과적으로 말하자면, 위험하다는 기준이 의도와는 다른 잘못된 데이터를 가져올까봐 위험하다는것이 아닌 내 의도와는 다른 매우 무거운 작업이 될 확률이 매우 농후하다는 점에서 위험한 코드가 되겠습니다
2
1. 당연히 member에 team을 연결하고 나면, 추후 em.find()로 team을 가져왔을 시 team.getMembers()에 잘 반영이 되게 됩니다.
강의에서 설명하고자 했던 부분은 한 트랜잭션이 끝나기 전에는, 논리적으로는 member에 team이 들어가면 자동적으로 team에 member도 추가되어야 정상이지만 그런 효과를 단순 setter로만 누릴수는 없기 때문에 매번 member.setTeam(team), team.addMember(member) 하는게 귀찮다면 두 개 기능을 합친 메서드를 만들면 편하다는 얘기를 하신 것 같습니다