HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
Spring Data
Spring Data
/
🧣
JPA(Java Persistence API)
/
🎽
Relation
/
👖
Relation 종류(@OneToOne, @OneToMany ..)
/
🪆
@OneToMany 단방향 문제점
🪆

@OneToMany 단방향 문제점

근데, 양방향으로 할 시, 연관관계의 주인에서 연관관계 세팅을 해주어야 한다는 귀찮음이 있음!
https://homoefficio.github.io/2019/04/28/JPA-일대다-단방향-매핑-잘못-사용하면-벌어지는-일/
  • @JoinColumn을 명시해야 함. 그렇지 않으면 JoinTable 전략을 사용하게 됨
단점
  • 엔티티가 관리하는 외래 키가 다른 테이블에 있음 (원래는 Many에 외래키 존재)
  • 본인 테이블에 외래 키가 있으면 엔티티의 저장과 연관관계 처리를 INSERT SQL 한번으로 끝낼 수 있지만, 다른 테이블에 외래 키가 있으면 연관 관계 처리를 위한 UPDATE SQL을 추가로 실행해야 함
    • insert into room (detailed_address, lot_address, post_code, road_address, capacity, description, host_id, name, price_per_day) values (?, ?, ?, ?, ?, ?, ?, ?, ?) insert into room_photo (file_name) values (?) insert into room_photo (file_name) values (?) update room_photo set room_id=? where id=? update room_photo set room_id=? where id=?
      마찬가지로 삭제 시에도, RoomPhoto 테이블에서 FK를 null 처리 해주는 update 쿼리 이후에 roomPhoto삭제, room 삭제를 실행함
  • 개발을 하다 보면 B를 만졌는데 A도 update sql문이 나가니 헷갈린다 → Team 데이터를 삽입하고 해당하는 연관관계에 대한 처리를 위해서 Member쪽도 손을 봐야 하니 Team과 Member 둘 다에 대해 sql이 나가는 것
  • 그래서 필요하다면 일대다 보다는 양방향 관계로 한다. ( B는 A가 필요 없더라도, 객체 지향적으로 손해를 보는 거 같지만) - 트레이드 오프
Member member1 = new Member("member1"); Member member2 = new Member("member2"); Team team1 = new Team("team1"); team1.getMembers().add(member1); team1.getMembers().add(member2); em.persist(member1); // INSERT-member1 em.persist(member2); // INSERT-member2 em.persist(team1); // INSERT-team1, UPDATE-member1.fk, UPDATE-member2.fk transcation.commit();
Member는 Team을 모르기에 Member 엔티티를 저장할 때는 MEMBER 테이블의 TEAM_ID가 null. 그 후 Team 엔티티를 저장할 때 Team.members의 참조 값을 확인해서 회원 테이블에 있는 TEAM_ID 외래 키를 업데이트 함

근데, 양방향으로 할 시, 연관관계의 주인에서 연관관계 세팅을 해주어야 한다는 귀찮음이 있음!

  • 원래 @OneToMany 단방향에서 cascade를 써버리면 손쉽게 db 영속화 하는 것이 가능함
public class Team{ @OneToMany(cascade=ALL) @JoinColumn("team_id") private List<Member> members = new ArrayList<>(); } public class Member{ } Member member1 = new Member("member1"); Member member2 = new Member("member2"); Team team1 = new Team("team1"); team1.getMembers().add(member1); team1.getMembers().add(member2); em.persist(team1); // INSERT-team1, insert member1, insert member2 // UPDATE-member1.fk, UPDATE-member2.fk transcation.commit();
  • 그러나 양방향으로 만들어 버리면 외래키 관리를 member에서 하기에 연관관계 설정 코드가 추가적으로 붙어야 함
public class Team{ @OneToMany(cascade=ALL, mappedBy = "team") // mappedBy는 필드이름 private List<Member> members = new ArrayList<>(); } public class Member{ @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name="team_id") // db에서 관리할 컬럼이름 private Team team; } Member member1 = new Member("member1"); Member member2 = new Member("member2"); Team team1 = new Team("team1"); team1.getMembers().add(member1); team1.getMembers().add(member2); member1.setTeam(team1); // 얘네가 연관관계의 주인이기에, 연관관계 설정 해주어야 함 member2.setTeam(team2); // 연관관계 설정 안하고 cascade만 하면 데이터는 들어가는데 // FK(team_id) 가 null임 em.persist(team1); // INSERT-team1, insert member1, insert member2 // UPDATE-member1.fk, UPDATE-member2.fk transcation.commit();