본문 바로가기

DB

JPA - 테이블 지향 모델링 vs 객체 지향 모델링 with jpa

예제 시나리오

  • 회원과 팀이 있다.
  • 회원은 하나의 팀에만 소속될 수 있다.
  • 회원과 팀은 다대일 관계이다.

객체를 테이블에 맞추어 모델링

연관관계가 없는 객체 모델링

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "TEAM_ID")
    private Long teamId;

    private String name;
}


@Entity
public class Team {

    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;

    private String name;
}

객체를 테이블에 맞추어 모델링을 하면 외래키 식별자를 직접 다뤄야 한다.

  • 객체자향적인 설계가 아님

저장

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    try {
        //객체 저장
        Team team = new Team();
        team.setName("TeamA");
        em.persist(team);
        Member member = new Member();
        member.setName("harris");
        member.setTeamId(team.getId());
        em.persist(member);

    }

조회

Member findMember = em.find(Member.class, member.getId());
Team findTeam = em.find(Team.class, findMember.getTeamId());
System.out.println("findTeamName" + findTeam.getName());

객체를 데이터 중심으로 모델링하면 협력 관계를 만들 수 없다!!

  • 테이블은 외래키로 조인을 사용해서 연관된 테이블을 찾는다.
  • 객체는 참조를 사용해서 연관된 객체를 찾는다.
  • 테이블과 객체 사이에는 이런 큰 간격이 있다.

객체지향 모델링

코드 상 큰 차이는 없고, 멤버의 필드로 teamId 대신 team을 갖게한다.

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;

    private String name;
}

이렇게 변화되면 보다 객체지향적으로 접근이 가능하다.

//저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("harris");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();

//조회
Member findMember = em.find(Member.class, member.getId());
System.out.println("findTeamName" + findMember.getTeam().getName());
  • 저장, 조회 시 teamId로 세팅, 조회하는 것에서 team을 직접 참조하는 것을 확인 할 수 있다.

FetchType.EAGER vs FetchType.LAZY

 

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;

위의 코드에서 객체간의 관계를 설정할 때 FetchType을 설정한 것을 볼 수 있다.

아래는 Eager, Lazy 로 세팅했을 때의 발생하는 쿼리이다.

LAZY

Hibernate: 
    select
        member0_.MEMBER_ID as MEMBER_I1_0_0_,
        member0_.name as name2_0_0_,
        member0_.TEAM_ID as TEAM_ID3_0_0_ 
    from
        Member member0_ 
    where
        member0_.MEMBER_ID=?
Hibernate: 
    select
        team0_.TEAM_ID as TEAM_ID1_1_0_,
        team0_.name as name2_1_0_ 
    from
        Team team0_ 
    where
        team0_.TEAM_ID=?

EAGER

Hibernate: 
    select
        member0_.MEMBER_ID as MEMBER_I1_0_0_,
        member0_.name as name2_0_0_,
        member0_.TEAM_ID as TEAM_ID3_0_0_,
        team1_.TEAM_ID as TEAM_ID1_1_1_,
        team1_.name as name2_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.TEAM_ID 
    where
        member0_.MEMBER_ID=?

LAZY의 경우는 member를 조회할 때 team을 바로 조회하지않고 team이 필요한 시점에 조회한다.

EAGER의 경우에는 member를 조회할 때 team도 한 번에 조회를 한다.

두 전략 모두 장단점이 있기 때문에 이를 잘 알고 사용해야 한다!!

 

Ref : 김영한님 inflearn 강의

'DB' 카테고리의 다른 글

Real MySQL 1장 ~ 3장  (0) 2022.05.23
JPA - 프록시  (0) 2021.09.12
JPA - @MappedSuperclass  (0) 2021.09.11
JPA - 다양한 연관관계 매핑  (0) 2021.09.11
JPA - 양방향 연관관계와 연관관계의 주인  (0) 2021.09.11