*김영한님의 JPA 기본 강의를 기반으로 작성하였습니다.
[연관관계 매핑 기초]
객체와 RDB 사이에는 패러다임의 차이가 있다.
객체는 "참조"로 연관된 객체를 찾고, 테이블은 "외래 키를 통한 Join"으로 연관된 테이블을 찾는다.
이러한 차이를 기반으로 객체의 참조와 테이블의 연관관계( 외래 키)의 매핑에 대해 파악해야한다.
모델링 시 "객체" 를 중심으로 돌아가게 설계하는 것이 "객체 지향적 설계" 이고, 만약 RDB 테이블에 객체를 맞춰지게
데이터 중심으로 설계하게 되면, 그것을 객체지향적으로 올바르지 못한 설계이다.
@JoinColumn은 DB 관점으로 보았을 때, 본인이 외래 키를 관리하며 상대 Table의 PK(Join할 때 사용)를 명시해주는 역할을 한다.
mappedBy 역시 특정 관계와의 연관관계를 나타낼 때 사용하는데, @ManyToOne과는 달리 연관관계의 주인이 아닌 쪽의 Class 내에서 사용한다. ( 보통 양방향 연관관계에서 사용한다. )
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name="article_id") //양방향이 아니면, mappedby로 다른쪽을 관계의 주인으로 설정 불가.
//상대방에 접근할 수 있어야 "관계의 주인" 이 될 수 있는데, 양방향이 아니라면 One쪽이 주인이 될 수 밖에 없다.
//따라서 ManyToOne이 필요 없더라도, 양방향으로 설정후 JoinColumn, mappedby로 Many쪽을 주인으로 할당하자.
~~~~~~~
[단방향 연관 관계]
우선 객체지향적이지 못하고, 테이블처럼 F.K를 기반으로 연관관계를 찾아나가는 설계에 대해 보자.
public class Member {
@Id
@GeneratedValue//(strategy = GenerationType.SEQUENCE,generator = "MEMBER_SEQ")
private Long id;
@Column(name = "USERNAME") //필드명과 컬럼명을 다르게 하고 싶을 때 설정해준다.
private String username;
@Column(name="TEAM_ID")
private Long teamId;
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name="TEAM_ID")
private Long id;
private String name;
}
Member객체는 소속된 team의 id 를 가지고 있다. ( F.K)
만약 어떠한 멤버가 소속된 팀에 대한 정보를 가져오고 싶다면 어떻게 해야될까?
Team team=new Team();
team.setName("TeamA");
em.persist(team);//영속성 컨텍스트에 들어가 영속상태가 되면 PK값이 세팅된다.
//멤버 정보 저장
Member member=new Member();
member.setUsername("member1");
member.setTeamId(team.getId());
em.persist(member);
//특정 멤버의 team 찾기
Member findMember= em.find(Member.class,member.getId());
Long findTeamId = findMember.getTeamId();
Team findTeam = em.find(Team.class, findTeamId);
매번 특정 member의 팀을 찾기 위해선 해당 member 객체에서 team id를 가져온 뒤, 다시 team id를 기반으로 team 객체를 찾는 작업을 수행해야한다.
이번엔 객체지향적으로, 객체 중심 설계를 진행해보자.
member 엔티티를 다음과 같이 수정하자.
이제 특정 멤버를 다시 구해보자.
Team team=new Team();
team.setName("TeamA");
em.persist(team);//영속성 컨텍스트에 들어가 영속상태가 되면 PK값이 세팅된다.
Member member=new Member();
member.setUsername("member1");
//member.setTeamId(team.getId());
member.setTeam(team); //team을 추가
em.persist(member);
//Member findMember= em.find(Member.class,member.getId());
//Long findTeamId = findMember.getTeamId();
//em.find(Team.class, findTeamId)
Member findMember= em.find(Member.class,member.getId());
Team findTeam=findMember.getTeam();//find할 필요 없이 getter로 바로 얻는다.
*주의: 실제 RDB는 당연히 테이블이기에, 테이블 자체의 변화는 없이 그대로 Member는 team_id라는 F.K를 통해 테이블을 참조한다.
getTeam() 만으로 해당 정보를 조회 가능하다. 이는 JPA를 통한 연관관계 설정으로 가능한 것으로, 만약 해당 멤버 객체를 find 하게 되면,
자동으로 Join Operation을 통해 연관된 객체들을 Join 해서 가져오게 된다.
아래는 em.find()로 member객체를 select하여 가져오는 과정에서 발생한 select 쿼리다.
select
member0_.id as id1_0_0_,
member0_.TEAM_ID as TEAM_ID3_0_0_,
member0_.USERNAME as USERNAME2_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_.id=?
연관된 Team이 Join되어 선택되는 것을 볼 수 있다.
여기서 드는 의문이 하나 있을 것이다.
매번 찾을 때마다, 연관된 객체를 "모두" 가져오게 되면, 성능이 저하되지 않을까?
하지만 Lazy로딩(지연 로딩)을 통해 이를 해결할 수 있다.
지연로딩: 연관된 객체가 실제로 필요한 시점까지 Join을 최대한 미루고, 필요할 때 Join 한다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="TEAM_ID")
private Team team;
위와 같은 설정을 적용해주면, member를 find 하는 시점에선, 사용된 member에 대해서만 select 쿼리가 나가고,
getTeam으로 Team이 필요한 시점에서 Team을 select하는 쿼리가 따로 나가게 된다.
Hibernate:
select
member0_.id as id1_0_0_,
member0_.TEAM_ID as TEAM_ID3_0_0_,
member0_.USERNAME as USERNAME2_0_0_
from
Member member0_
where
member0_.id=?
Hibernate:
select
team0_.TEAM_ID as TEAM_ID1_1_0_,
team0_.name as name2_1_0_
from
Team team0_
where
team0_.TEAM_ID=?
만약 연관관계를 수정하고 싶다면?
ex) 특정 멤버의 팀이 바뀐 경우
그냥 단순하게 setter를 통해 객체를 바꿔주면, 자동으로 테이블의 F.K값이 바뀌게 된다.
findMember.setTeam(team2);
[양방향 연관관계와 연관 관계의 주인]
Team에서도 소속된 member들에 대해서 알기 위해, List로 Member들을 저장한다.
Team 객체에 소속된 멤버들을 저장하는 리스트를 추가해 양방향 연관 관계로 만든다.
@OneToMany(mappedBy = "team")
private List<Member> members= new ArrayList<Member>();
이제 Team에서 getmembers()를 통해 멤버들을 가져올 수 있다.
여기서 mappedBy란 무엇일까?
이를 이해하기 위해선 객체와 테이블이 맺는 연관관계의 차이에 대하여 이해해야 한다.
객체 연관관계 = 2개
회원 -> 팀 연관관계 1개(단방향)
팀 -> 회원 연관관계 1개(단방향) • 테이블 연관관계 = 1개
회원 <-> 팀의 연관관계 1개(양방향)
테이블은 F.K와 P.K를 연결해서 팀 소속의 멤버들, 그리고 멤버의 팀에 대해 알 수 있다. (사실 어차피 양쪽이 아닌 한쪽에만 F.K를 둬서 양쪽을 파악 가능하기에 방향이라는 개념이 딱히 없다)
정리하자면 객체에는 양방향 관계가 없고, 단방향 2개를 통해 양방향으로 만들어주는 것이지만,테이블은 F.K만으로 두 테이블의 연관관계를 관리할 수 있다. (양방향)
ex)A라는 멤버의 팀이 변경되었다. 이때 양방향 연관관계에서 변화를 갱신하려면 어떻게 해야할까?
테이블의 관점에선, member의 F.K값만 새로운 팀의 P.K로 변경하면 끝난다.
그럼 어떤 객체를 주인으로 두어야할까?
보통 F.K를 가진쪽이 주인이 된다. ( 보통 DB관점에서 테이블을 보면 , Many To One 관계에서 Many가 F.K를 가지게 된다.
따라서 보통 Many쪽을 주인으로 둬야한다. 만약 One쪽이 주인이면, One쪽 객체 하나 변경시 모든 Many 들에게 insert가 들어감.)
현재 Join의 기준은 Team_id이고, Member 테이블에서 Team_id라는 외래키를 가지고 Join하게 되므로 Member를 주인으로 설정한다. (Many To One 관계가 헷갈리는 경우, 그냥 Many쪽을 주인으로 설정해주면 된다.)
다시 위에 적어둔 Team 클래스의 변경사항을 보자
@OneToMany(mappedBy = "team")
private List<Member> members= new ArrayList<Member>();
mappedby를 통해 member와 주종관계를 설정해주고, member를 주인으로 만든다.
**주의
이제 Member가 주인이고 Team은 주인이 아니기에, Team은 F.K인 Team_ID를 읽을 수만있고, 수정은 할 수 없다.
연관관계의 주인은 F.K 보유자.
Member_id. <> Orders 는 order가 주인
Many To Many 를 One To Many, Many To One 으로 풀어낸다.
orders와 order_item, item과 order_item으로 구성되는 One to Many Many to One 관계의 주인은 Order_item
만약 양방향관계를 설정하고 싶다면
Orders <> Orer_Item 을 단방향 2개로 양방향으로 만들고, Order_item <> Item을 단방향 2개로 양방향으로 만드는작업을 수행하면 된다.
이 예제의 경우, Order는 해당 주문에서 어떤 Item이 있는지 OrderItem을 통해 알 수 있게 양방향으로 설정(orderItems 리스트를 통해)
Item은 알 필요가 없다는 가정하에 단방향으로 OrderItem에 아이템 정보를 제공해주게 설계했다.
이제 OrderItem을 통한 다 대 다 관게 형성에 대해 살펴보자
@ManyToOne
@JoinColumn(name="ORDER_ID") //생략 가능. 자동으로 객체이름_id로 생성된다.
private Order order;// 실제 테이블에선 관계를 가지는 테이블의 P.K를 F.K로써 보유하게된다
@ManyToOne
@JoinColumn(name="MEMBER_ID")
private Member member;
* @JoinColumn
@JoinColumn은 엔티티간 조인과는 관계없이 F.K의 이름을 지정하기 위해 사용하는 것이고, 생략이 될 경우 알아서 @ManyToOne의 대상이 되는 엔티티의 이름_id를 대상으로 삼는다.
** 사실 대부분의 설계들은 단방향만으로 가능하다(그리고 양방향 관계는 시스템이 고려할 사항이 많아 복잡해지는 원이기도 하다)
하지만 실무에서 Order조회할때 OrderItem들을 같이 조회하는 기능을 구현하는 경우, 이를 일일이 JPQL로 구현하는 것은 어려움이 있다. 따라서 최대한 단방향을 사용하되 조회를 편하게, JPQL 작성을 편하게 하기 위해 등등 특정 부분에서만 양방향을 사용하자.
**관계의 주인쪽 객체 와 대응하는 테이블에는 F.K가 들어가게되고( Member 엔티티에 Team의 P.K인 team_id가 F.K로 들어가는 것처럼) 주인이 아닌쪽에서는 만약 양방향 관계를 만들고자 객체를 형성해준다해도 테이블에는 영향이 없다. ( Order에서 OrderItem들의 내역을 확인하고자
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems=new ArrayList<OrderItem>();
와 같이 참조 객체를 추가하더라도, 테이블에는 영향이 없다.
**대부분 Many쪽이 관계의 주인이고, 최대한 단방향 관계 위주로 설계하기에, 대부분
@ManyToOne
@JoinColumn(name= 필드이름)
~~~~~~~~~~~~~~~~~~~~
이런식으로 관계를 설정해주고, One쪽에서도 Many쪽을 알아야한다면
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems=new ArrayList<OrderItem>();
이렇게 추가해주면 된다.
[다양한 연관관계 매핑]
다대일: @ManyToOne: 주인이 many 쪽으로 설계
일대다: @OneToMany : 주인이 One 쪽으로 설계
일대일: @OneToOne
다대다: @ManyToMany
와 같은 JPA의 매핑 어노테이션은 "데이터베이스와 매핑" 을 위한 어노테이션이다. 따라서 데이터베이스 관점에서의 다중성으로 고려를하자.그리고 "실무 환경" 에서 @ManyToMany 는 사용하지 않는다.
[Many To One]
[One To Many] 이 모델은 권장하지 않는다. 객체 관점에서는 One 쪽에서 Many를 알고 싶지만, Many는 One쪽을 알지 못하는 설계를 할 수도 있다.
하지만 실제 테이블에선 F.K가 무조건 Many쪽으로 들어감.
여기서 객체와 테이블의 차이 때문에 주인이된 One쪽에서 반대편 테이블의 외래키를 관리하는 특이한 구조로 동작하게된다.
@JoinColumn을 꼭 사용해야한다( 그렇지 않으면 Join 테이블 방식으로 중간에 테이블을 하나 추가한다.
ex) team.addMember(member)로 팀에 멤버를 추가하고 team이 저장되면, 해당 member쪽으로 가서 F.K를 설정해줘야한다.
이에 따라 update 쿼리가 한번 더 나가게된다.
더 심각한 문제는 team만 변경해도 member에 변경이 들어가게되서 전체적인 코드를 이해하는데 어려움이 생기고
(team 을 수정했는데 왜 member에 쿼리가 들어가지?) 이는 실무 같은 많은 테이블이 복잡하게 얽혀있는 상황에서 이해를 더욱 복잡하게 만든다(유지보수에서의 어려움 발생).
One To Many 단방향 매핑을 사용하지 않고 차라리 Many To One 양방향 매핑을 사용하는게 성능적으로 아쉽더라도 더 나은 경우가 많다. ( many to one 양방향 : Many -> One, One -> Many로 비효율적이라도 차라리 이게 나은경우가 있다.
+@
OneToMany 단방향 VS. ManyToOne 양방향
OneToMany: One 쪽에서 Many에 접근 가능(One쪽 객체를 가지고 모든 Many쪽을 얻을 수 있다.)
ex) 관리자 <> 유저. : 관리자는 모든 유저들에 접근할 수 있다.
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name="article_id")
//관계의 주인은 해당 관계안의 다른 테이블에 접근할 수 있어야한다.
//OneToMany 단방향은 One쪽에서만 Many에 접근가능하기에 , One이 관계의 주인이 되고,
//실제 RDB에선 Many쪽에 F.K가 생기기에 문제가 발생.
//따라서 Many -> One 이 필요하지 않더라도 양방향으로 만들어서 Many를 주인으로 설정하자
결국
@ManyToOne + @JoinColumn ( many 쪽에 부여 ) + OneToMany(mappedby ~~) 로 Many 쪽에 F.K를 두는가
아니면
@OneToMany+ @JoinColumn() 으로 One쪽에 F.K를 두는 가 이다.
일 대 다 매핑의 문제점은, 데이터베이스 테이블의 특성상 F.K는 Many 쪽 테이블에 들어가게 되는데, One쪽에
JoinColumn으로 조인을 하게되어 실제론 Many쪽에 들어있는 F.K가 One쪽에 있는 것처럼 논리적으로 만들어지고,
실제로 One쪽에서 F.K에 접근하면, Many쪽에 하나하나 쿼리가 들어가게 된다.
ManyToOne: Many쪽에서 One에 접근 가능(Many쪽 객체가 One에 대해 알 수 있다.
ex) 모든 멤버는 자신의 소속팀을 조회할 수 있다.
테이블과 마찬가지로, Many쪽에 F.K가 들어가게 되어 OneToMany의 문제가 개선된다.
여기서 양방향을 활용해 ManyToOne을 뒤집어 OneToMany를 만들어서 One 쪽에서 Many에 대해 알 수 있게 만드는 것.
**단방향, 양방향 관계 잡기 요약
단방향: JoinColumn 으로 Many쪽에 참조할 객체 필드를 생성
양방향: 위에 더해 @~~~(mappedby~)와 참조할 객체 필드를 생성
[일 대 일]
데이터베이스 입장에선 외래 키에 unique 제약조건이 추가되는 것.
어느 쪽에 외래키를 넣어도 무방. 단, 좀더 select 가 많이되는 주 테이블에 두는 것이 좋은 경우가 많다. ( F.K를 다른 테이블에서 찾지 않아도 되게) 예를들어 멤버가 1개의 보관함을 가지는 비지니스 모델이 있는데, 보통 멤버가 중심으로 동작하게 될 것이고, select도 더 많이 될것. 따라서 F.K가 Member쪽에 들어가게 설계하는 것이 좋을 것이다. 하지만 주테이블에 필드값이 점점 많아지고, 아직 연관관계가 붙지 않은 것 null 값이 들어가는 등 조금 지저분해질 수 있다.
@JoinColumn과 @~~~(mappedby )
@JoinColumn은 DB 관점으로 보았을 때, 본인이 외래 키를 가지고 있으며 관리하며 상대 Table의 PK(Join할 때 사용)를 명시해주는 역할을 한다. @JoinColumn은 생략가능한데, 이 경우,
@mappedBy 또한 특정 관계와의 연관관계를 나타낼 때 사용하는데, @ManyToOne과는 달리 연관관계의 주인이 아닌 쪽의 Class 내에서 사용한다. 보통 양방향 연관관계에서 사용한다.
주 테이블에 외래키가 존재
주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음객체지향 개발자 선호
JPA 매핑 편리
장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
단점: 값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키가 존재
전통적인 데이터베이스 개발자 선호
장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨: 대상 테이블을 뒤져봐야 대상 테이블이 연결되어있는지 확인 가능하다. (어차피 쿼리로 대상 테이블 가서 확인해야하기에, 즉시 로딩한다)
+ 양방향으로 만들어야한다.( JPA에서 지원x)
[Many To Many]
@ManyToMany 어노테이션을 통한 매핑은 쓰면 안된다! 알아만 두자.
이런식으로 연결테이블을 1대 다, 다 대 1 관계로 풀어서 만들어야한다.
하지만 객체는 각각 컬렉션을 둬서 다 대 다 관계가 가능하다.
@ManyToMany
@JoinTable(~~~) 를 통해 중간다리 역할을 하는 Member_Product 같은 테이블들이 자동생성된다.
하지만 이 테이블은 코드상으로 숨겨져 있어 파악하기 힘들고, 추가적인 필드를 할당할 수 없다.
(member_produect 테이블에는 두 테이블의 F.K만 들어있다)
따라서 그냥 Member_product 테이블을 엔티티로 승격 시킨 뒤,
@ManyToOne, @OneToMany 으로 다 대 다 관계 만들면 된다.
(중간다리 테이블) (대상 테이블)
따라서 실제로는 단방향이면 중간 테이블역할을할 엔티티를 manyToOne으로,
양방향이면 Member, Product에 OneToMany(mappedby) 추가.
여기서 포인트: 여기서 member_id, 그리고 produect_id를 F.K이자 중간다리 역할을 하는 order의 P.K로 사용할 수 도 있지만 (제약 조건 해결),
P.K가 다른 곳에 종속되면 이후 비즈니스 변경으로 인한 수정에서 문제점들이 생겨날 수 있기에, 그냥 generted value로 랜덤하게 할당한 key를 사용하는게 장기적 관점으로 좋을 수 있다(그리고 제약조건이 필요하면 그냥 추가하면 된다).
[상속 관계 매핑]
관계형 데이터베이스는 상속관계가 없다. 슈퍼 타입, 서브 타입 관계라는 유사한 기능을 이용해서 상속관계와 매핑한다.
왼쪽은 슈퍼타입 서브타입 관계(logical), 오른쪽은 객체 상속관계
상속관계는 결국 하위에서 상위를 상속받아 상위의 특성을 가지는 것인데, 위의 예시에서 album을 조회한다면, 상위의 item이 가지는 필드인 id, 이름, 가격을 알 수 있어야한다.
ex) 자동차(상위) <- 전기차(하위) : 자동차라는 특성에 "전기" 라는 특성이 추가되는 것.
상속관계 매핑
슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법
각각테이블로변환->조인전략
통합 테이블로 변환 -> 단일 테이블 전략
서브타입 테이블로 변환 -> 구현 클래스마다 테이블 전략
디폴트는 단일 테이블 전략으로 하나의 테이블에 모아준다(extends 등으로 상속관계 존재시 자동으로 모아줌).
만약 전략을 변경하고 싶은경우, 상위 엔티티 클래스( 위 예시의 경우 item)에
@Inheritance(strategy = InheritanceType.JOINED)
이런식으로 어노테이션을 부여해주면된다.
@Inheritance(strategy=InheritanceType.XXX)JOINED: 조인 전략 ( 이것만 바꾸면 간편하게 전략 수정이 가능하다)
JOINED: 조인 전략
SINGLE_TABLE: 단일 테이블 전략
TABLE_PER_CLASS: 구현 클래스마다 테이블 전략@DiscriminatorColumn(name=“DTYPE”)
@DiscriminatorColumn(name=“DTYPE”)
상위 클래스에서 작성하는 것. 어떤 자식 클래스에 의해 사용되는지에 대한 Column이 추가된다.
ex) album 객체에 select가 발생 시, Item의 값들을 가져와야하는데, 이때는 DTYPE라는 이름을 가진 컬럼이 album으로 바뀐다.
->어떤 하위 클래스로 인해 불려졌는지 알 수 있다.
*주의점: ddl-auto 값을 create로 주는 경우, 매번 애플리케이션 시작 시점에서 테이블을 새롭게 초기화하는데, 외래 키 제약 조건이 있는 테이블에는 이 방법이 적용되지 않을 수 있다. ( 외래 키가 존재하는 테이블을 함부로 지울 수 없다) 따라서 create에서 시작시점에서 drop을 수행하면 에러가 발생할 수 있다. 해결법으로, update( drop 하지 않는다) 혹은 create-drop(완전 제거) 등의 값으로 변경하면 해결할 수 있다. 혹은 초기화 데이터를 import.sql 등에 넣어서 매번 초기화 데이터를 넣어주며 테스트하는 방법도 있다.
@DiscriminatorValue(“XX”)
디폴트는 엔티티명. 만약 어떠한 엔티티 클래스의 이름과 매핑되는 테이블의 이름이 다를 경우, 해당 어노테이션으로 표기해줘야한다.
ex) ALBUM 엔티티가 ALB 테이블에 매핑 될 경우.
@DiscriminatorValue(“ALB”) 와 같이 표기해주면 된다.
조인 전략
그때 그때 필요한 자식 테이블을 join으로 가져옴. 가장 메인으로 사용하는 전략.
정규화, 객체지향적 특성 등등 다양한 이점이 있다.
장점
- 테이블 정규화 (내가 item만 필요하면 item만 빼올 수 있다.
- 외래 키 참조 무결성 제약조건 활용가능 • 저장공간 효율화
단점
- 조회시조인을많이사용,성능저하
- 조회 쿼리가 복잡함 (단일 테이블은 심플하게 가능)
- 데이터 저장시 INSERT SQL 2번 호출
단일 테이블 전략
논리 모델을 1개의 테이블로 합쳐버린다.
평균적으로 join보다 빠르지만 테이블이 커진다.
보통 join을 기본으로 깔고, 단순하거나 확장 가능성이 많이 없어보인다면 단일 테이블 전략을 사용하고, 중요하거나 복잡한건
join 전략으로
장점
- 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
- 조회 쿼리가 단순함
-단점•
- 단일테이블에 모든 것을 저장하므로 테이블이커질수있다.상 황에 따라서 조회 성능이 오히려 느려질 수 있다.
- 자식 엔티티가 매핑한 컬럼은 모두 null 허용
구현 클래스마다 테이블 전략
[좋지 않은 전략]
item 테이블 없이 하위 테이블들이 각각 item의 컬럼을 모두 가지게 한다.
하지만, 부모타입으로 조회한다면? (특정 아이템의 아이디로 find 등등) -> album, movie, book 모든 테이블을 뒤져야한다.
거의 사용하지 않는 전략이다, 참고만하자.
@mappedSuperClass
상속관계 매핑과 무관. 공통 정보를 객체에서 설정한다 (id, name, createDate 등) db에선 개별적으로 관리됨.
공통 attribute를 BaseEntity등의 클래스에 만들고 사용할 객체에서 상속받아서 사용하게 한다. (이때 BaseEntity에 들어가는 어노테이션이 @mappedSuperClass) 만약 공통 사항을 바꾸고 싶으면 BaseEntity에서 바꾸면 된다.
- 상속관계 매핑X
- 엔티티X, 테이블과 매핑X
- 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
- 조회, 검색 불가(em.find(BaseEntity) 불가)
- 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장 (단독으로 사용할 일이 없으면 추상 클래스로 표시해주는 것으로 오해를 막는다)
- 테이블과 관계 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할
- 주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통 으로 적용하는 정보를 모을 때 사용
참고: @Entity 클래스는 엔티티나 @MappedSuperclass로 지 정한 클래스만 상속 가능
'Spring boot' 카테고리의 다른 글
[JPA] Part 4 (값 타입) (0) | 2023.03.10 |
---|---|
[JPA] Part 3 프록시와 연관관계 (0) | 2023.03.10 |
[JPA 기본] Part1 (영속성 컨텍스트, 기본 매핑 ) (0) | 2023.03.08 |
API 서버 구성과 JWT를 통한 인증, 인가 (1) | 2023.01.30 |
Spring Boot 컨트롤러와 Client간의 관계 정리 (0) | 2023.01.27 |