이러한 엔티티를 가진 DB를 만들어 보자
1. 일단은 Member와 Team이라는 테이블 2개가 필요하다.
2. Member는 MEMBER_ID를 PK값으로 가지고 Team은 TEAM_ID를 PK값으로 가진다.
3. TEAM_ID는 Foregin key값이다.
package com.codingbox.jpashop.relation;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter @Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
// @Column(name="TEAM_ID")
// private Long teamId;
/*
* 1대다의 개념을 객체에게 알려야 하는데,
* DB기준으로 1대다의 개념을 알려줘야한다.
* @ManyToOne : 여기선 Team의 개념이 하나이다.
* @JoinColumn(name = "TEAM_ID") : 관계 컬럼을 적어준다. TEAM_ID와 조인해야 한다.
*/
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
- @Id 어노테이션은 JPA(Java Persistence API)에서 사용되는 엔티티 클래스의 필드를 식별자(Identifier)로 표시하는 역할이다. @Id 어노테이션을 사용하여 엔티티 클래스의 필드를 식별자로 지정하면 JPA가 해당 필드를 엔티티의 주요 식별자(primary key)로 사용 가능하다.
- @GeneratedValue 은 전략 사용이 가능하다. 즉 sequence가 자동으로 생성된다.
sequence를 생성하고 있다.- @Column(name = "MEMBER_ID")을 이용하여 pk값을 MEMBER_ID로 설정한다.
- @ManyToOne
@JoinColumn(name = "TEAM_ID") 여기서 TEAM_ID 를 fk값으로 받는다.
- 물론 @Column(name="TEAM_ID")
private Long teamId; 이렇게 객체를 따로 만들어 설정해 주어도 되지만 위의 방법이 좀 더 간편하다.
package com.codingbox.jpashop.relation;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter @Setter
public class Team {
@Id
@GeneratedValue //sequence 값 세팅
@Column(name="TEAM_ID")
private Long Id;
private String Name;
}
Team 테이블은 사실 간단하다. 그냥 pk값 지정하는 것 말고는 크게 신경쓸 부분이 없다.
위와 동일하게 @Id
@GeneratedValue //sequence
@Column(name="TEAM_ID") 이용하여 코드를 구성하자.
DB의 모습이다.
package com.codingbox.jpashop;
import com.codingbox.jpashop.relation.Member;
import com.codingbox.jpashop.relation.Team;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf
= Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
tx.commit();
em.close();
emf.close();
}
}
이 틀을 기억하자. main을 위한 기본적인 설정이다. 트랜잭션을 생성하고 커밋하는 과정이며, 아직 엔티티 클래스의 인스턴스를 생성하지는 않았다.
현재는 비어있는 트랜잭션을 커밋하는 것이므로 데이터베이스에 아무런 변경 사항이 없다.
package com.codingbox.jpashop;
import com.codingbox.jpashop.relation.Member;
import com.codingbox.jpashop.relation.Team;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf
= Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Team team = new Team();
team.setName("TeamA");
//영속 상태가 되면 pk의 값이 세팅이 된 후에 영속상태 된다.
em.persist(team);
Member member = new Member();
member.setUsername("member1");
//member.setTeamId(team.getId());
member.setTeam(team); // 아이디만 가져오는게 아니라 전부
em.persist(member);
//select
//어떤 멤버의 pk값을 아는 상태에서 그 멤버가 어느 팀 소속인지 알고 싶을 때 확인
// Member findMember = em.find(Member.class, member.getId()); //여기서 팀의 정보까지 다 가져온다. member정보만 가져오는게 아님. foregin 키까지 연관되어 있어서.
// Long findTeamId = findMember.getTeamId();
// Team findTeam = em.find(Team.class, findTeamId);
// System.out.println("findTeam : " + findTeam.getName());
//강제로 db쿼리를 보고 싶을때
em.flush();
em.clear();
//어떤 멤버의 pk값을 아는 상태에서 그 멤버가 어느 팀 소속인지 알고 싶을 때 확인
Member findMember = em.find(Member.class, member.getId()); //여기서 팀의 정보까지 다 가져온다. member정보만 가져오는게 아님. foregin 키까지 연관되어 있어서.
Team findTeam = findMember.getTeam(); //여기서도 팀의 정보 가져옴. 아이디만 가져오는게 아니라 전부. 위에서는 id값을 가져오지만 이건 전부 다 가져온다.
System.out.println("findTeam : " + findTeam.getName());
tx.commit();
em.close();
emf.close();
}
}
이것이 연관관계이다.
1.Team team = new Team();
team.setName("TeamA"); 일단 team객체를 만들어 주자. 다음은 TeamA라는 이름을 세팅해준다.
2. em.persist(team); 영속상태를 만들어 주자 이렇게 함으로써 트랜잭션 커밋 시 데이터베이스에 반영할 수 있다.
3. Member member = new Member();
member.setUsername("member1");
//member.setTeamId(team.getId()); 멤버 객체를 만들고 유저 이름을 member1로 세팅.
주석 처리한 부분은 member테이블에서 team테이블에 있는 id값을 가져오는 역할을 한다.
바로 team에서 가져오는 것이 아닌 연관관계를 이용해 id값을 가져오는 역할
3-1. member.setTeam(team); 이 코드는 위에서 id만 가지고 온 것과 다르게 team테이블의 전체를 다 가져온 것이다.
System.out.println("findTeam : " + findTeam.getName()); 따라서 이 코드의 결과는 뭘까? team의 이름을 가져오는 것이 요구조건이다.
주석 처리한 부분만 봐도 사실 이해는 충분하다.
조금 더 추가적으로 분석하자면,
em.find() 메서드는 member를 데이터베이스에서 조회한다. 이때 Member 엔티티와 Team 엔티티 간의 관계가 설정되어 있으므로, Member를 조회할 때 연관된 Team 정보도 함께 가져온다.
이 메서드가 db와 연동하는 역할을 한다고 볼 수 있다.