@Entity@DatapublicclassMember{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)@Column(name="MEMBER_ID")privateLongid;@Column(name="USERNAME")privateStringusername;@ManyToOne@JoinColumn(name="TEAM_ID")//외래키Teamteam;//연관관계 편의 메소드//java의 getter/setter 관례때문에 setXXX가 아닌 다른 동사로 사용할 필요가 있다.publicvoidchangeTeam(Teamteam){this.team=team;team.getMembers().add(this);}}
@Entity@DatapublicclassTeam{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)@JoinColumn(name="TEAM_ID")privateLongid;@Column(name="NAME")privateStringname;@OneToMany(mappedBy="team")//참조하는 객체명privateList<Member>members=newArrayList<>();//연관관계 편의 메소드//(※ 연관관계 편의 메소드가 양쪽에 다 있으면 문제과 될수 있으니 기준을 둬서 한 쪽에만 둬야한다.)/*
public void addMember(Member member) {
member.setTeam(this);
members.add(member);
}
*/}
Teamteam=newTeam();team.setName("TeamB");em.persist(team);MembernewMember=newMember();newMember.setUsername("member3");newMember.setTeam(team);em.persist(newMember);//INSERT 실행 (IDENTITY)//★ em.persist 이후에 아래 2줄이 동작해야지, DB에서 데이터를 깔끔하게 값을 가져올수 있다.em.flush();em.clear();MemberfindMember=em.find(Member.class,newMember.getId());//SELECT 실행if(findMember!=null){System.out.println("조회 결과가 있습니다.");List<Member>members=findMember.getTeam().getMembers();//SELECT 실행for(Membermember:members){System.out.println(member.getId()+" / "+member.getUsername());}}else{System.out.println("조회 결과가 없습니다.");}tx.commit();
일대다 (1:N)
권장하지 않는 모델
실무에서 많이 사용되지는 않는다.
일대다 중에서 일(1)에 해당하는 객체가 연관 관계의 주인이다.
객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
@JoinColumn을 꼭 사용해야 한다.
그렇지 않으면 조인 테이블 방식을 사용한다. (중간에 테이블을 하나 추가한다.)
추가로 발생하는 UPDATE 쿼리로 인해 성능상 좋지 않다.
엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리해야 하다보니 구조가 더 복잡해진다.
단방향
일대다 단방향 매핑의 단점
엔티티가 관리하는 외래 키가 다른 테이블에 있음
연관관계 관리를 위해 추가로 UPDATE SQL 실행
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 권장된다.
양방향
일대다 양방향 매핑의 문제점
공식적으로 존재하는 매핑 방법이 아니다.
@JoinColumn(insertable=false, updatable=false)
읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법이다.
일대다 양방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 권장된다.
일대일 (1:1)
일대일 관계는 그 반대도 일대일
주 테이블이나 대상 테이블 중에서 외래 키를 갖고 있을 테이블을 선택할 수 있다.
외래 키에 데이터베이스 유니크(UK) 제약조건을 추가한다.
주 테이블에 외래 키 단방향
다대일(@ManyToOne) 단방향 매핑과 유사하다.
대상 테이블에 외래 키 양방향
다대일 양방향 매핑 처럼 외래 키가 있는 곳이 연관관계의 주인이다.
반대편은 mappedBy를 적용한다.
대상 테이블에 외래 키 단방향
단방향 관계는 JPA가 지원되지 않는다.
대상 테이블에 외래 키 양방향
일대일 주 테이블에 외래 키 양방향과 매핑 방법은 같다.
정리
주 테이블에 외래 키
주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
객체지향 개발자 선호
JPA 매핑 편리
장점
주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
단점
값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키
대상 테이블에 외래 키가 존재
전통적인 데이터베이스 개발자 선호
장점
주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점
프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨
다대다 (N:M)
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 한다.
@ManyToMany 사용
@JoinTable로 연결 테이블 지정
단방향, 양방향 가능
편리해 보이지만 실무에서 사용하지 않는다.
연결 테이블이 단순히 연결만 하고 끝나지 않는다.
필요한 데이터가 추가될 수도 있다.
연결 테이블을 엔티티로 승격시켜서 다대다 매핑의 한계를 극복할 수 있다.
공통 코드
EntityManagerFactoryemf=Persistence.createEntityManagerFactory("hello");//애플리케이션 전체 공유 (persistence.xml 참조)EntityManagerem=emf.createEntityManager();//한번 쓰고 버려야함, 쓰레드간 공유하지 않음EntityTransactiontx=em.getTransaction();//조회를 제외한 DML 작업시 필수로 사용tx.begin();try{//실행 내용}catch(Exceptione){e.printStackTrace();tx.rollback();}finally{em.close();}emf.close();