여러가지 키 매핑을 객체 변수에 지정할 수 있음.
@Id
@Column(name = "oooo")
@Enumerated(EnumType.STRING) <- number 말고 string 으로 하는게 국룰
@Temporal(TemporalType.TIMESTAMP) <- TIMESTAMP 로 하는 편
@Lob
@Transient
~ key mapping 어노테이션 ~
@GeneratedValue(strategy = GenerationType.AUTO)
id 값을 자동으로 생성.
- DB 에 위임하여 직접 하도록.
- strategy = GenerationType.IDENTITY
- 영속성 주입을 할때, db에 insert 함수가 실행됨
- DB 시퀀스 오브젝트 사용
- @SequenceGenerator
- sequence 용 table
- DB에서 키 50개를 미리 가져오는 설정도 있음 (allocationSize)
- 추가적으로 더 필요해지면, 그때 또 요청.
- DB 키 생성용 table
- @TableGenerator 필요
- 데이터 DB 에는 db함수가 들어가지 않고, key만을 위한 함수가 실행.
해당 내용들은 객체와 DB를 매핑하기 위한 annotation 들
우리가 필요한 것은
[1] 객체를 데이터(Table) 중심으로 설계
@Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "TEAM_ID") private Long teamId; private String name; private String city; private String street; private String zipcode; }
[2] 객체 중심으로 설계
@Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @ManyToOne @JoinColumn(name = "TEAM_ID") private TeamModel team; private String name; private String city; private String street; private String zipcode; }
private Long teamId; private TeamModel team; 이 두개의 차이임. 객체를 포함하여 객체를 구성하기 위함!
양방향인 경우에는 주인을 정해주어야함. (여러가지 이유로)
외래키가 있는 곳을 주인(Owner)으로 설정!! (하는 것을 권장하심)
mappedBy 를 통해 주인을 지정해준다.
정확히는 mappedBy가 있으면, 주인의 반대편!
@OneToMany(mappedBy = "team")
-> 나는 team 에 의해 관리되고 있어!
- 데이터 수정 효율성.
- jpa server function 실행 명확함 제공.
- Lazy 기능 용이
(1) 우리 jpa는 이 코드가 생각처럼 작동하도록 하지 못함!
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member);
em.persist(member);
(2) 이렇게 해줘야 우리 생각처럼 작동함 (즉, 주인 객체에서 set 이 일어나야함)
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
(1), (2)의 차이에서 보듯이, jpa도 이정도까지는 객체화 지원을 안해주나봄
(어려워서라기 보다는, 아마 내부 로직/설계 상의 단점, 한계가 실제로 있지 않을까...)
아이러니 하게도, flush, clear 를 해주고 나면 원하는 대로 작동.
flush() 가 호출되고 나면 상관이 없겠지만은,
우리가 EntityManager 의 transaction의 commit 혹은 flush 되기 전에,
객체 다운 활용을 하고 싶다면, ((1) 처럼만 하면, getMembers()가 업데이트 안되어 있음)
(3) transaction 동안, 혹은 flush 되기 전에 생각처럼 사용될 수 있도록!!
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member); // 이 부분도 필요할 것이다.
member.setTeam(team);
em.persist(member);
활용!!
>> 실무에서는 두개를 같이 써야하는게 종종 누락이 생기기 마련...
>> 연관관계 편의 메소드 생성
Member.java 파일 setTeam 수정
pulic void setTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
관례상 함수명을 setTeam => changeTeam 으로 하는 것을 권장.
member의 메소드에 하던, team 의 메소드로 만들던 그건 선택!!
무한루프 조심 (toString() 이나, lombok, JSON 생성 라이브러리)
김영한 개발자님 강조
엔티티는 절대로 컨트롤러나 api 에 반환하지 마라! 문제가 될 여지가 큼.
DTO 로 변환해서 반환 하는 것을 추천!!
테이블
-> 테이블에는 방향이라는 개념이 없음. 어차피 Join 이기 때문에
객체
-> 객체에서는 단방향, 양방향이 있음 (참조 여부)
테이블은 외래 키 하나로 연관관계를 맺지만,
객체는 참조가 2군데가 있어서 외래키를 관리할 곳 지정!
그래서 mappedBy를 추가한다고 해서 테이블 형태가 바뀌는 것은 아님!
테이블과 객체사이 jpa 에서 인지를 하기 위해 있는 것 (search query 작동)
사용하다가, search 하는 경우가 너무 많다! 하면 추가하는 거임
일대다 에서 '다' 쪽을 주인이 아닌 '일' 쪽을 주인으로 하게될 경우
-> 의외로 객체에서는 자주 보이는 일
--> 허나 DB 에서 이렇게 관리 되는 건 말이 안됨!
---> 주인은 '일'이 맞으나, 외래키는 '다'에서 관리
query 를 한번 중간에 사용해 줘야하는 단점! '일'쪽에서 어떤 변화가 생겼는지를 detect 하고, 해당 Table 에 id 값이 같은 곳으로 가서, update를 해주어야함
- (덧) 다 쪽에 해당 함수 추가하여 쓰는 것도 있음
- @JoinColumn(insertable=false, updatable= false)
- 마지 다대일 양방향 매핑처럼 됨. 읽기 전용으로 해줌으로서.
실무에서 이런 식의 객체와 테이블의 미스매칭은 유지보수가 상당히 헷갈려질 수 있다. 수십개의 테이블이 존재하는 상황에서, 이걸 전부 외워두고, 실수 안해야하는 것!
실제로 비즈니스 상으로 일대다 에서 일 을 주인으로 해야하는 설계가 필요할 수 있다. 하지만 유지보수 측면에서 다 를 주인으로 해주는 것이 좋아보임. 차라리 다대일 양방향으로 설계하는 것으로 설계 (김영한 개발자님)
어디에 외래키를 넣어도 상관 없음
Member.java
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
Locker.java
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
@Column(name = "NAME")
private String name;
}
대상 객체에도 양방향으로 넣어서, 대상테이블에서 관리..
사실상 주 테이블 외래키 단방향하고 똑같음!
재밌는 Trade off 를 소개해주심
DB 작업자 의 입장에서
외래키를 어디서 관리할까?
1. Locker 로 관리하면, 추후에 한 회원이 여러 Locker 를 가질 수 있게 되면, 쉽게 변경 가능하겠네
2. 근데, 여러 회원이 하나의 Locker 를 사용하게 된다면? Member에 외래키가 있는게 맞는걸?객체 개발자의 입장에서
막상 실무를 해보면, Member는 항상 불러오는 값중 하나이고, Member가 외래키를 가지는게!
각자 장단점이 있음... 이건 추후에...!