JPA ) 자바 ORM 표준 JPA 프로그래밍 - 5

GoRuth·2025년 4월 16일

JPA

목록 보기
5/8

연관관계 매핑 전 핵심 키워드

  1. 방향
  • 단방향 : 둘 중 한 쪽만 참조하는 것
  • 양방향 : 양쪽 모두 서로 참조하는 것
  1. 다중성 (M / N)
  • 다대일 : M 여러개가 N 하나에 속한다.
  • 일대다 : N 여러개가 M 하나에 속한다.
  • 일대일 : M 하나가 N 하나에 속한다.
  • 다대다 : M 여러개가 N 여러개에 속한다.
  1. 연관관계의 주인
  • 연관관계의 주인 : 객체를 양방향 연관관계로 만들면 주인을 정해야 한다.

단방향에서의 연관관계

객체

  • 참조(주소)로 연관관계를 맺음
  • 객체 A는 A.b필드로 B객체와 연관관계
  • A는 B 파악 가능, B는 A 파악 불가능
  • 객체 그래프 탐색
    • 객체는 참조를 사용해서 연관관계를 탐색

테이블

  • 테이블은 외래키로 연관관계를 맺음
  • A 테이블은 B_ID 외래 키로 팀 테이블로 연관관계
  • A와 B는 양방향, 양쪽은 외래키로 Join 가능

객체와 테이블의 연관관계의 차이!
1. 참조를 통한 연관관계는 언제나 단방향
-> 결국, 연관관계를 추가해서 양쪽 참조를 해야 함
2. 단, 참조를 통한 양쪽 참조 != 양방향 관계
-> 서로 다른 단방향 2개

객체 관계 매핑

@Entity
@Data
public class A {
	@Id
	@Column(name = "A_ID")
	private Long id;

	@ManyToOne
	@JoinColumn(name = "B_ID")
	private B b;

	private String aa;
}

// 🔺는 A 클래스 , 🔻는 B클래스

@Entity
@Data
public class B {
	@Id
	@Column(name = "B_ID")
	private Long id;

	private String bb;
}
  • @ManyToOne
    • 다대일 관계라는 매핑 정보
    • 연관관계를 매핑할 때, 다중성을 나타내는 Annotation 필수
  • @JoinColumn
    • 조인 컬럼은 오래키를 매핑할 때 사용
    • name속성
      -> 매핑할 외래키 지정
    • 생략가능
      -> 생략 시, 찾는 기본 전략 (필드명_참조테이블컬럼명)

연관관계 사용

저장

  • A Entity에서 B Entity를 참조 후 저장한다고 가정
    -> JPA는 참조한 B의 식별자를 외래 키로 사용해서 등록쿼리 생성
    -> 실행된 SQL에는 B의 식별자가 입력

제거

  • 삭제 전 기존의 연관관계를 먼저 제거해야 함
    -> 안하면 외래 키 제약조건으로 DB Error

양방향 연관관계

객체

  • 일대다 관계는 여러 건과 연관관계를 맺을 수 있음
    -> Collection을 사용해야 함 (List, Set, Map 등등)

테이블

  • DB은 외래 키 하나로 양방향 조회가능, 이전 관계와는 차이 ❌

객체 관계 매핑

@Entity
@Data
public class A {
	@Id
	@Column(name = "A_ID")
	private Long id;

	@ManyToOne
	@JoinColumn(name = "B_ID")
	private B b;

	private String aa;
}

// 🔺는 A 클래스 , 🔻는 B클래스

@Entity
@Data
public class B {
	@Id
	@Column(name = "B_ID")
	private Long id;

	@OneToMany(mappedBy = "b")
	private List<A> b = new ArrayList<>();

	private String bb;
}

연관관계의 주인

  • 테이블은 외래 키 하나로 연관관계 관리

  • 객체는 두 객체간 서로를 참조
    ->어떤 관계를 사용해서 외래 키를 관리해야할까?

    JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래 키 관리를 지시

  • 두 연관관계 중 하나를 연관관계의 주인으로 정해야 함

    • 주인 ⭕ : DB 연관관계와 Mapping, 외래키를 관리 (CUD)
    • 주인 ❌ : Only Read
    • mappedBy로 Setting -> 주인이 아닌 Entity에서 사용
      💡 다대일, 일대다 관계는 항상 다 쪽이 주인!

양방향 연관관계의 주의점

  • 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것

public class Main {
	public static void main(String[] args) {
		EntityManagerFactory emf =
			Persistence.createEntityManagerFactory("myJpaUnit");
		EntityManager em = emf.createEntityManager();
		EntityTransaction transaction = em.getTransaction();

		try {
			transaction.begin();

			B bc = new B(1L, new ArrayList<>(), "firstB");
			A ac1 = new A(1L, null, "firstA");
			A ac2 = new A(2L, null, "secondA");

			bc.getA().add(ac1);
			bc.getA().add(ac2);

			// 비영속 -> 영속
			em.persist(bc);
            // DB에 데이터 저장
			transaction.commit();
			
            // find -> 1차 캐시에 영속 Entity 존재하므로 1차캐시에서 Get
            /*
            B(
              id=1, 
              a=[
                A(id=1, b=null, aa=firstA), 
                A(id=2, b=null, aa=secondA)
              ], 
              bb=firstB
            )
            */ 
			System.out.println(em.find(B.class, 1L));

			// 영속 -> 준영속
			em.detach(bc);

			// find -> 1차 캐시에 영속 Entity ❌, DB에서 1차 캐시에 영속 Entity 저장 후 1차 캐시에서 Get
            // B(id=1, a=[], bb=firstB)
			System.out.println(em.find(B.class, 1L));
		} catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {
			em.close();
		}
	}
}

그럼 주인 아닌 곳에 설정 X?

  • 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안정
    -> 순수한 객체 상태에서 심각한 문제 발생!
    💡 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주자
profile
Backend Developer

0개의 댓글