강의 링크
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
객체와 테이블 매핑
@Entity
@Entity가 붙은 클래스는 JPA가 관리, 엔티티라고 한다.
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수다.
- 주의
- 기본 생성자 필수 (파라미터가 없는 public 또는 protected 생성자)
- final 클래스 , enum , interface, inner 클래스 사용이 불가능함.
- 저장할 필드에 final 사용이 불가능함.
@Table
엔티티와 매핑할 테이블을 지정한다.
데이터베이스 스키마 자동 생성
- DDL을 애플리케이션 실행 시점에서 자동 생성한다.
- 테이블 중심 → 객체 중심
- 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.
- 이렇게 생성된 DDL은 개발 장비에서만 활용한다.
- 생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용한다,
데이터 베이스 스키마 자동 생성 - 주의
- 운영 장비에는 절대 create , create-drop, update를 사용하면 안된다.
- update문도 alter문이 전송되면 data table lock이 걸려서 서비스가 잠시 중단될 수도 있다.
- 개발 초기단계는 create 또는 update
- 테스트 서버에는 update 또는 validate (엔티티와 테이블이 잘 매핑되었는지 검증)
- 스테이징 운영 서버는 validate 또는 none
운영서버로 스크립트를 넘길 경우, 자동으로 생성된 DDL 스크립트문을 다듬어서 넘겨서 오류 없게 만드는 것이 좋다.
DDL 생성 조건
- 제약조건 추가 가능 : nullalbe = false, unique = true, length = 10
- DDL 생성 기능은 스키마 자동 생성 때만 사용되고 JPA 실행 로직에는 영향을 주지 않는다.
필드와 컬럼 매핑
- @Column : DB에 있는 컬럼명과 매핑
- arg
- insertable = True, updatable = true : 삽입 여부 또는 등록 여부 (default = true)
- nullable = false : not null 제약조건
- unique : @Table의 uniqueConstranints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 떄 사용 (하지만 해당 속성 이름을 랜덤값으로 지정하기 때문 Table의 uniqueConstranints를 사용하자)
- lenth : 데이터 길이 제한
- columnDefinition : varchar(100) default ‘EMPTY’ 같이 입력하면 컬럼 정보를 직접 줄 수 있다.
- @Enumerated : DB는 Enum 타입을 지원하지 않으므로 JPA가 해당 부분을 매핑.
<br/>
- arg
- **EnumType.ORDINL** : enum으로 정의한 값들을 숫자 index로 표기
→ 운영 시 **매우 위험** : 데이터가 추가될 경우 index가 변경되기 떄문에
- **EnumType.STRING** : default이며 **꼭 이 타입을 사용해야**한다.
<br/>
- @Temporal : DATE , TIME , TIMESTAMP(날짜 + 시간) 값을 부여할 수 있음.
- 속성 타입을 LocalDate ( 년월 ) , LocalDateTime (년월 + 시간)으로만 해주어도 적용된다.
- @Lab : varchar를 뛰어넘는 큰 데이터에 해당 속성을 사용할 경우.(BLOB ,
- @Transient : DB와 매핑되지 않는 속성을 부여할 경우.
기본키 매핑
@GenerateValue
@GenerateValue : @Id에만 사용되며 값이 자동 생성되도록 한다.
arg
IDENTITY : 데이터베이스에 위임(autoincrement)
SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용
- 데이터베이스 시퀀스 : 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(예: 오라클 시퀀스)
TABLE : 키 생성용 테이블 만들어내서 SEQUENCE를 흉내내는 방법, @TableGenerator 필요
해당 키를 관리, 조회하는 테이블을 생성한다.
- 장점 : 모든 데이터베이스에 적용 가능
- 단점 : 성능이 떨어진다.
- AUTO ; 방언에 따라 자동 지정, 기본값
권장하는 식별자 전략
- 기본키 제약조건 : null 아님, 유일, 변하면 안된다.
- 미래까지 이 조건을 만족하는 자연키를 찾기 어렵기 때문에 대리키를 사용하자.
- 주민등록번호도 기본 키로 적절하지 않다. → 정부에서 지침을 바꾼다던지.. 변수가 항상 존재함.
- 권장 : Long + 대체키 + key 생성전략 사용.
IDENTITY 전략 - 특징
기본 키 생성을 데이터베이스에 위임 → id를 알기 위해서는 데이터베이스에 삽입되어야만 한다!
→ 그러면 JPA의 영속성 컨텍스트에서 1차 캐시에 id를 저장할 경우 어떻게 하는걸까?
→ 예외적으로 em.persist 호출할 시점에 바로 insert 쿼리를 날려버린다.
→ 이후 생성된 id를 조회하고 1차 캐시에 id값을 저장한다.
SEQUENCE 전략 - 특징
삽입될 때 id값을 가져오는 방식이 아니라 SEQUENCE Table에서 해당 key index값을 조회해서 1차 캐시를 변경할 수 있게된다 → 버퍼링 방식이 가능해진다.
차라리 DB에서 값을 조회하고 업데이트하는 것보다 바로 ID를 JPA가 관리하고 INSERT문을 보내면 효율적인 것 아닐까?
- arg로 allocationSize를 설정한다.
- allocationSize = 50으로 설정한다. (1 ~ 51)
- 처음에만 select 문을 두번 호출한다 (1로 업데이트 되었는지 , 끝 범위 51으로 업데이트 되었는지 확인)
- 해당 seq 테이블의 index값이 50이 넘어갈 때 까지는 추가로 네트워크 요청이 이루어지지 않아 성능이 향상된다.
무조건 allocationSize를 크게 하는 건 좋은 걸까?
서버가 갑자기 종료된 시점의 공백이 발생할 수 있기 때문에 적절하게 사용하는 것이 좋다.
JPA가 시퀀스 번호 1부터 50까지를 미리 할당받았다.
서버가 1부터 25까지의 시퀀스 번호를 사용하다가 갑자기 종료되었다.
서버가 재시작되면 JPA는 다시 새로운 시퀀스 범위를 할당받는다. 이 경우 다음 시퀀스 범위는 51부터 시작된다.
이로 인해 시퀀스 번호 26부터 50까지는 사용되지 않고 공백으로 남게 된다. 이러한 공백은 데이터의 일관성과 관리 측면에서 문제가 될 수 있다. 특히, 시퀀스 번호가 중요한 의미를 가지는 경우(예: 영수증 번호, 주문 번호 등)에는 이러한 공백이 문제가 될 수 있다.