일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 부트스트랩 #Bootstrap #웹개발첫걸음 #스파르타코딩클럽
- 스파르타코딩클럽 #코딩 #jQuery #Ajax
- 스파르타코딩클럽 #크롤링 #스크래핑
- 항해99솔직후기 #항해99 #부트캠프추천
- #내일배움단 #코딩프로젝트 #국비지원 #내일배움카드 #스파르타코딩클럽
- Today
- Total
이모저모
JPA - Entity mapping, 연관관계의 주인 본문
자바 ORM 표준 JPA 프로그래밍 강의(김영한) 필기
🖍 객체와 테이블 매핑
- @Entity가 붙은 클래스는 JPA가 관리.
- 기본 생성자가 필수적으로 있어야 함.(public, 또는 protected 생성자)
- final, enum, interface, inner 클래스 사용하면 안됨.
🖍 데이터베이스 스키마 자동생성
DDL(Data Definition Language): 데이터 전체 골격을 결정/정의하는 역할의 언어
spring으로 작업하면서, application.properties에 이런 식으로 작성했었는데, update외에도 create, create-drop, validate(엔터티와 테이블이 잘 매핑되어 있는지만 확인) 등의 옵션이 있다.
spring.jpa.hibernate.ddl-auto=update
운영장비에는 절대로! create, create-drop, update 사용해서는 안된다고 함!
단계별 권장 설정(by 김영한님)
- 개발초기에는 create, update
- 테스트 서버는 update, validate
- 스테이징과 운영 서버는 validate 또는 none
DDL 생성기능
제약조건추가 @Column(nullable = false, length = 10, unique=true) 이런 식으로 db에 영향.
JPA의 실행로직에는 영향을 주지 않는다고 함.
🖍 필드와 컬럼 매핑
@Column(name = "name", nullable=false, ...)
컬럼 매핑
@Enumerated(EnumType.STRING)
enum 타입을 매핑
✔︎ 주의 EnumType.ORDINAL(이게 default) 사용하지 않기 _권장 by 김영한님
- 왜 int형으로 저장되는 기본(ORDINAL설정)을 사용하면 안되는가?
- 비즈니스 로직에 의해 예컨대 회원의 유형이 추가될 수도 있다. 이때 새로 추가된 유형이 0번째에 추가되면, 이전에 0으로 입력된 친구랑 db상에서 구분을 할 수 없게 되는 실수(?) 가능하다. 차라리 메모리를 조금더 쓰더라도 확실하고 안전하게 STRING으로 enum이 들어가게 해놓는 것이 데이터 관리에 좋다.
@Transient
매핑 무시. 데이터베이스에는 반영 안하고 싶고 메모리에서만 임시로 계산해보거나 하고 싶을 때.
🖍 기본키 매핑
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
strategy 종류
- IDENTITY
- 기본 키 생성을 데이터베이스에 맡기는 것. 그런데 AUTO_INCREMENT의 경우 INSERT SQL 실행 후에야 ID 값을 알 수 있으므로, IDENTITY 의 경우는 em.persist()시점에 INSERT SQL을 즉시 실행하여 식별자 조회 가능. 그러다보니 IDENTITY 전략의 경우 모아서 query들을 넘기는 것이 불가능하다는 단점(?!)이 있음.
- SEQUENCE : 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트. 오라클, H2, PostgreSQL 에서 사용
- AUTO: 방언에 따라 자동 지정, 기본값
🖍 연관관계 매핑
✔︎ 테이블의 FK는 애초부터 양방향이고, 객체의 참조는 단방향이므로 서로에 대한 참조들을 만드려면 단방향 두 개를 만들어야 한다.
- 테이블 차원에서는 FK만 있으면 이쪽에서 저쪽, 저쪽에서 이쪽으로의 오고감이 가능하다. (사실상 테이블엔 방향이라는 것이 없음)
- 하지만 객체 차원에서는 member 객체로부터 team에 대해 참조하고 있다고 해서, team객체에서 자연스럽게 member에 대한 참조/탐색이 가능한 것은 아니다.
✔︎ 양방향 관계(즉 엄밀히 말해서 단방향 두개)를 만들 경우 주의점!
- 예를 들어, Member (n) --------- (1) Team. 이렇게 두 엔티티가 있다고 해보자.
- 나는 member a의 팀을 team A 가 아니라 B로 변경하고 싶다.
- 그렇다면 나는 Member 엔터티에 접근해서 변경해야 할까, Team 엔터티에 접근해서 변경해야 할까?
- (이 고민이 가능한 이유는, Member에서도 ManyToOne으로 참조하는 Team이 존재하고, Team에서도 OneToMany로 참조하는 List<Member>가 존재하기 때문이다.)
- 이런 애매함을 해결하기 위해서는, 결정해야 한다. 무엇을? "연관관계의 주인"을!
- 연관관계의 주인만 연관관계에 대해서 수정 등을 할 수 있고, 주인이 아닌 쪽에서는 '조회만 가능'!
- 그렇다면 연관관계의 주인은 어떻게 정할 것인가?
- 답은 "외래키를 가지고 있는 곳!!!"
- Member와 Team의 관계에서 보자면, many쪽인 member가 팀에 대한 외래키를 갖는다고 볼 수 있다.
- (주의할 점은, "연관관계의 주인"이라는 어휘의 느낌 때문에 더 묵직한(?) Team이 주인이 아닐까 싶지만 그렇지 않다는 것!)
- 그래서 team.getMembers().add(member)이런 식으로만 처리하면, team은 연관관계의 주인이 아니므로, 이 양방향 관계에 반영이 안된다..!!!!!
- ==> 양방향 매핑시 연관관계의 주인 쪽에 값을 입력해야 한다.
- 다만, 정말 객체지향답게 하자면 늘 양쪽 모두에 값을 입력해주어야 한다고 함!!
- 물론 주인쪽에만 값을 입력해도, jpa가 양쪽 테이블에 다 sql query를 날려준다.
- 하지만 혹시라도 sql에 들어가지 않은 상태에서 (즉 1차캐시에 머물러 있는 상태에서) 주인쪽(예-member)으로만 값을 변경하고, 반대편(예-team)에는 변경하지 않은 채로 이 둘을 불러내본다면, team은 쿼리 반영이 안 된 채로 1차캐시에 머물러있던 아이가 호출된다. 그래서 안정적으로 또 객체지향스럽게 처리하려면 양쪽 모두에 값을 입력해야 한다.
'coding > Java, Spring' 카테고리의 다른 글
JPA의 데이터 타입 (0) | 2022.02.22 |
---|---|
JPA _ proxy, eager loading, lazyloading (0) | 2022.02.21 |
JPA - 영속성 컨텍스트 (0) | 2022.02.21 |
절차/객체/관점 지향 프로그래밍 (0) | 2022.02.21 |
request scope와 provider, proxy (0) | 2022.02.17 |