양방향 매핑시 연관관계를 양쪽에서 맺어주지 않으면, 한 트랜잭션 내에서 제대로 조회가 되지 않을 수 있다. 연관관계 메서드를 설정하자.
상황을 간략히 아래 예시로 표현해보았다.
1. 부모 트랜잭션 A, 자식 트랜잭션 B, 자식 트랜잭션 C가 있는 상황에서 실행 순서는 A -> B -> C 순서로 진행된다.
2. 자식 트랜잭션 B에서 생성한 객체를 자식 트랜잭션 C에서 사용하고자 한다.
3. 자식 트랜잭션 C에서 객체를 조회하는 과정에서 에러가 발생했다.
// 부모 트랜잭션 A
@Transactional
public void parentMethod() {
childOneMethod();
childTwoMethod();
}
// 자식 트랜잭션 B
@Transactional
public void childOneMethod() {
Member member = new Member("m1", "Daisy");
Team team = new Team("t1", "Seoul");
member.setTeam(team);
...
}
// 자식 트랜잭션 C
@Transactional
public void childTwoMethod() {
Team team = repository.findByName("Seoul");
team.getMembers(); // 에러 발생
...
}
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "TEAM_ID") // 연관관계의 주인 (외래키를 저장하는 곳)
private Team team;
}
@Entity
public class Team {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy = "team") // Member.team 연관관계의 주인
List<Member> members = new ArrayList<Member>();
}
// Team에는 연관 관계 설정을 하지 않았다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");'
// Member에서는 연관 관계 설정을 했다.
member.setTeam(team);
em.persist(member)
Team findTeam = em.find(Team.class, team.getId());
// 커밋하지 않았기 때문에 조회하면 null이 나온다.
findTeam.getMembers();
원칙적으로는 연관관계의 주인쪽인 Member에서만 연관관계를 맺어도, 양방향으로 사용이 가능하다. 하지만, 양쪽에서 연관관계를 설정해주지 않으면 이와 같이 한 트랜잭션 내에서 제대로 조회가 되지 않는 문제가 발생한다. 이러한 상황을 방지하기 위해서는 연관관계 메서드를 사용해 양방향으로 연관관계를 매핑해줘야 한다.
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "TEAM_ID") // 연관관계의 주인 (외래키를 저장하는 곳)
private Team team;
/* 연관관계 메서드 설정 */
public void setTeam(Team team){
this.team=team;
team.getMembers().add(this);
}
}
Reference: https://jiwondev.tistory.com/227