신경 쓸 것!!
JPA - 객체와 테이블을 매핑!!
why JPA??
SQL 중심 개발의 문제점
현재 시대는 객체를 관계형 DB에 저장
-> sql 중심의 개발이 된다.
패러다임의 불일치
객체 vs 관계형 DB
객체 지향 언어는 래퍼런스 저장할 수 있다.
하지만 DB에는 래퍼런스 저장이 불가능하다.
(예시, 자바 컬렉션에 객체를 저장하면
해당 객체 내부의 객체들 모두 조회 가능!
하지만 DB에서 조회한 객체는 직접 매핑을
해줘야만 가능하다.)
-> 자바 컬렉션처럼 db에 저장할 수는 없나?
JPA - Java Persistence API
자바 진영의 ORM 기술 표준
ORM - Object-Relational Mapping (객체 관계 매핑)
영속성 컨텍스트 (Persistence Context)
영속, 비영속, 준영속
@Entity가 붙으면 JPA가 관리하는 클래스 (public or protected 기본 생성자 필수)
데이터베이스 방언을 활용해 DB에 맞는 적절한 DDL을 생성
hibernate.hbm2ddl.auto
.create, drop + create
.create-drop, drop + create + drop
.update, 변경분만 적용
.validate, 엔티티 - 테이블 정상 매핑됐는지만 확인
.none
주의!! 운영 장비에는 절대 create, create-drop, update 사용 X
개발 초기 단계는 create 또는 update
테스트 서버는 update 또는 validate
스테이징과 운영 서버는 validate 또는 none
@Column
여러 옵션으로 설정 가능
@Id -> pk 지정
@GeneratedValue -> 자동 입력 / 전략 - identity, sequence, table
추천 :Long + 대체키 + 키 생성 전략
identity 전략은 id 생성을 DB에 위임 -> JPA는 null값으로 id값을 넘기기에 영컨에 저장할 id가 없다.
(하지만 영컨의 1차 캐시에서는 엔티티를 id로 구분했다 -> 커밋시점이 아니라 바로 sql 날려서 id값 받아온 뒤 1차캐시에 등록)
sequence 전략은 em.persist()시에 db에 저장돼있는 next_sequence받아와서 setId()한 뒤에 영컨에 저장
-> 매번 저장할 때마다 db에 접근하면 성능 이슈?? 그래서 allocationSize = 50
-> 메모리에서 next_seq를 저장해가다가 seq == 50 -> db에 접근해 next_seq (100)을 받아옴.
이 방식은 여러 서버가 켜있어도 문제가 없다. (본인의 max를 받아 놓기에)
엔티티에 객체가 아닌 객체의 id를 저장한다면, 객체 중심 < 테이블 중심의 설계가 된다. + 객체 조회하려면 계속
em.find필수
따라서 엔티티에 객체의 id가 아닌 객체를 저장해야한다!!
객체 - 테이블 연관관계
객체 - 참조 ~~ 테이블 - 외래 키
단순히 테이블 간에 외래 키로만 참조가 단방향으로 이루어지는 경우에 @xTox 어노테이션 + @JoinColumn으로
매핑이 가능하다.
양방향 연관관계, 두 테이블 간에 단순히 외래 키로만 참조가 단방향이 아닌 서로 참조가 이루어질 때!
(member, team 참조 | team, memberList 참조)
테이블에서는 외래 키로 양 테이블을 왔다갔다 가능!!
객체는 불가능하다. -> 양방향 연관관계
List members 에 @OneToMany(mappedBy = "team" ) -> 참조 연결이 될 객체 명 매핑
객체 : 회원 -> 팀 & 팀 -> 회원 | 사실 서로 다른 단방향 관계가 2개
테이블 : 회원 <-> 팀 | 방향X, 외래키 하나로 두 테이블 연관관계 관리(join)
회원, 팀 모두 서로를 참조하고 있기에 테이블의 외래키 (team_id)를 관리를 누가할 것인가에 문제가 생긴다.
결론부터 얘기하자면, 외래 키를 가지고 있는 테이블의 엔티티가 관리한다. 그리고 그런 엔티티를
연관관계의 주인이라고 명명한다.
그 이유는 회원 (팀 참조), 팀 (많은 회원 참조) 상황에서
회원이 팀을 바꿨다.
회원이 주인-> 회원 엔티티, 팀 참조 변경 -> 회원 테이블, 팀 id 변경
팀이 주인 -> (일단 벌써 복잡하다...) 팀 엔티티, 회원 리스트에서 회원 삭제 + 회원 엔티티 팀 참조 변경 -> 팀 테이블도 같음
팀이 주인이 된다면 회원이 팀을 변경하는 상황에 너무 많은 변경 사항이 필요하다. 하지만
회원이 주인이라면 간단히 팀 id만 변경하면 되니 너무나도 직관적이다!!
그리고 반드시 연관관계 주인에는 값을 set해야한다!!!!
차라리 양방향 연관관계에서는 둘다 넣어버리는게 편하다.
-> 까먹지않게 연관관계 편의 메서드를 정의하자!! (member.setTeam() 안에다가 team.getMembers.add하도록!)
(em.flush()를 하고 1차 캐시에 업데이트를 하지 않는다면
1차 캐시에 없기에 조회가 안된다.) !!!항상 1차 캐시 신경쓰자!!
예제!!
고급 매핑
상속관계 매핑
관계형 DB에는 상속관계 x (유사한 것은 슈퍼타입 - 서브타입)
조인전략 / 단일 테이블 전략 / 구현 클래스마다의 테이블 전략
1은 정규화도 돼있고, 저장공간 효율
2은
3은 Item타입으로 조회할 때, 모든 테이블을 모두 검색해야해서 비효율!!
위 전략들을 바꿔도 코드 손댈 것이 없다... -> 개꿀 ㅎ