728x90
Spring 숙련주차 팀과제
팀 깃허브: https://github.com/sparta-are-you-t/hobby-bungae
소감
기본 요구사항 구현에 충실했고 테스트 코드까지 작성해서 테스트해봤으나 막상 postman으로 테스트해봤을 때 돌아가지 않았다.
그리고 entity 간의 다대다 관계가 2가지가 존재했고 아직 JPA 연관관계와 영속성, 양방향/단방향 등에 대한 개념이 확실히 잡혀있지 않다보니 이를 이용해 로직을 구현하는 과정에서 많은 어려움을 겪었다.
이렇게 팀 과제를 마무리한 것이 아쉬워서 혼자서 이번 팀 과제를 수정하고 JPA에 대해 더 공부해보고자 한다.
- 무조건 다대다 관계로 구현?
개인 담당 튜터님과 짧게 면담을 진행하면서 튜터님께서 이번 팀 과제 코드를 잠깐 봐주셨는데 사용자인 User 엔티티와 취미인 Hobby 엔티티를 N:M이 아닌 1:N 관계로 구현하는 것이 더 좋지 않겠냐는 조언을 받았다.
지금까지는 실제로 N:M 관계이면 무조건 N:M 관계로 구현해야 한다는 생각만 가지고 있었는데 구현하고자 하는 기능에 따라 1:N 또는 N:1로 구현할 수도 있다는 것을 알게 되었다.
그래서 혼자서 팀 과제를 수정할 때는 다대다 관계를 최대한 줄여서 구현해봐야겠다는 생각이 들었다.
JPA 프로그래밍 책 참고
엔티티 매니저팩토리와 엔티티 매니저
- 데이터베이스를 하나만 사용하는 경우 일반적으로 EntityManager Factory를 하나만 생성
- 매니저 팩토리 생성
- EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
- METE-INF/persistemce.xml에 있는 정보를 바탕으로 EntityManagerFactory를 생성
- 엔티티 매니저 생성
- EntityManager em = emf.createEntityManager();
- 엔티티 매니저 펙토리는 여러 스레드가 동시에 접근해도 안전하므로 공유 가능
- 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 공유하면 안됨
연관관계 매핑
- 다대일(N:1) 속성
- optional: 기본값 true. false일 경우 연관 엔티티가 항상 있어야 함
- fetch: 기본 값 즉시로딩. 지연 로딩
- cascade: 영속성 전이 기능 사용
- 단방향 연관관계
- 회원 -> 팀 : 연관관계 설정
- Member.class
- @ManyToOne
- @JoinColumn(name="TEAM_ID")
- private Team team; // 연관관계 매핑
- public void setTeam(Team team){ this.team = team; } // 연관관계 설정
- Member.class
- 회원(Member) N : 1 팀(Team)을 저장하는 코드
- Team team1 = new Team("team1", "팀1");
- em.persist(team1);
- Member member1 = new Member("member1", "회원1");
- member1.setTeam(team1); //연관관계 설정
- em.persist(member1);
- 회원의 팀을 조회하는 코드(객체 그래프 탐색)
- Member member = em.find(Member.class, "member1");
- Team team = member.getTeam();
- 회원의 팀을 수정
- Member member = em.find(Member.class, "member1");
- member.setTeam(team2);
- 연관관계 삭제
- Member member1 = em.find(Member.class, "member1");
- member1.setTeam(null);
- 회원 -> 팀 : 연관관계 설정
- 양방향 연관관계
- 회원 <-> 팀 : 연관관계 설정
- Team.class
- @OneToMany(mappedBy = "team")
- private List<Member> members = new AllayList<Member> ();
- 팀에서 회원을 조회
- Team team = em.find(Team.class, "team1");
- List<Member> members = team.getMembers();
- 데이터베이스 테이블은 외래 키 하나만으로 양방향 연관관계를 맺는다.
- 엄밀히 말하면 객체에는 양방향 연관관계라는 것이 없다.
- 연관관계의 주인: 외래 키를 관리할 수 있음: Member
- 연관관계 저장
- Team team1 = new Team("team1", "팀1");
- em.persist(team1);
- Member member1 = new Member("member1", "회원1");
- member1.setTeam(team1); //연관관계 설정
- team1.getMembers().add(member1);
- em.persist(member1);
- 양방향 관계 설정 코드를 묶어서 사용
- Member.class
- public void setTeam(Team team) { this.team = team; team.getMembers().add(this); }
- Member.class
- 팀을 새로 설정할 때 기존 관계 제거 후 설정
- if(this.team != null) { this.team.getMembers().remove(this); }
- this.team = team;
- team.getMembers().add(this);
- Team.class
- 양방향 매핑 시 주의 사항: 무한루프
- 서로 getTeam(), getMember()를 호출하는 경우 등
- 엔티티를 JSON으로 변환할 때 자주 발생 -> 어노테이션을 제공
- Lombok 라이브러리를 사용할 때도 자주 발생
- 회원 <-> 팀 : 연관관계 설정
- 우선 단방향 매핑을 사용하고 반대 방향으로 객체 그래프 탐색 기능이 필요할 때 양방향을 사용하도록 코드를 추가하는 방식으로!
- @OneToMany 단방향의 문제점
- 다른 테이블에 외래키가 있으면 연관관계 처리를 위한 UPDATE SQL을 추가로 실행해야 한다.
- 일대다 단방향보다는 다대일 양방향 매핑을 사용하자
- 다대일 양방향(회원 Member <-> 팀 Team)
- Member.class
- public void setTeam(Team team) {
- this.team = team;
- if(!team.getMembers().contains(this)){ // 무한루프에 빠지지 않도록 체크
- team.getMembers().add(this);
- }
- }
- Team.class
- public void addMember (Member member) {
- this.members.add(member);
- if(member.getTeam() != this) { // 무한루프에 빠지지 않도록 체크
- member.setTeam(this);
- }
- }
- Member.class
- @OneToMany 단방향의 문제점
- 다대다 N:N
- 연결 엔티티 사용
- 비식별관계: 받아온 식별자는 외래 키로만 사용하고 새로운 식별자를 추가 -> 추천 !
- 회원(N) - 주문 - 저장(N)
- 저장하는 코드
- em.persist(member1);
- em.persist(productA);
- Order order = new Order();
- order.setMember(member1);
- order.setProduct(productA);
- em.persist(order);
- 조회하는 코드
- Long orderId = 1L;
- Order order = em.find(Order.class, orderId);
- Member member = order.getMember();
- Product product = order.getProduct();
- 연결 엔티티 사용
'TIL' 카테고리의 다른 글
[231130] 팀과제 수정 (0) | 2023.11.30 |
---|---|
[231129] 프록시와 영속성, 스프링 데이터 JPA (0) | 2023.11.29 |
[231122] ResponseDto, RequestDto에 Getter가 필요한 이유 (0) | 2023.11.22 |
[231120] Spring 숙련주차 개인과제 해설 (0) | 2023.11.20 |
[231117] HTTP 요청 ~ 응답의 과정 (Feat. todoapp) (0) | 2023.11.17 |