티스토리 뷰
JPA 기본 정리
Entity 매핑
속성 : name
- JPA에서 사용할 엔티티 이름 지정
- 기본값 : 클래스 이름을 그대로 사용
- 같은 클래스 이름이 없으면 가급적 기본값을 사용한다.
1.Table 매핑
@Table은 엔티티와 매핑할 테이블 지정
name - 매핑할 테이블 이름
catalog - 데이터베이스 catalog 매핑
schema - 데이터베이스 schema 매핑
uniqueConstraints - DDL 생성 시에 유니크 제약조건 생성
2. 데이터베이스 스키마 자동생성 - 주의
운영 장비에는 절대 create, create-drop, update 사용 X
테스트 서버는 update 또는 validate
스테이징과 운영 서버는 validate 또는 none
3.DDL 생성 기능
제약조건 추가 : 회원 이름은 필수, 10자 초과 X
@Column(nullable = false, length = 10)
유니크 제약조건 추가
@Table(uniqueConstraints = {@UniqueConstraint( name = "NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE} )})
- DDL 생성 기능은 DDL을 자동 생성할 때 만 사용
JPA의 실행 로직에는 영향을 주지 않음
- DDL 생성 기능은 DDL을 자동 생성할 때 만 사용
4. 매핑 어노테이션 정리
@Column - 컬럼 매핑
@Temporal - 날짜 타입 매핑
@Enumerated - enum 타입 매핑
@Lob - BLOB, CLOB 매핑
@Transient - 특정 필드를 컬럼에 매핑하지 않음
5. 연관관계 매핑
다대일 [N:1]
*다대일 양방향 매핑
@중요
- 외래 키가 있는 쪽이 연관관계 주인
- 양쪽을 서로 참조하도록 개발
- 실무에 가장 많이 쓰임
일대다 [1:N]
*일대다 양방향
@정리
- 이런 매핑은 공식적으로 존재 X
- @JoinColumn(insertable = false, updatable = false)
- 다대일 양방향을 사용하자
N:M(다대다) 관계는 1:N, N:1로
- 테이블의 N:M 관계는 중간 테이블을 이용해서 1:N, N:1
- 실전에서는 중간 테이블이 단순하지 않다.
- @ManyToMany는 제약 : 필드 추가X, 엔티티 테이블 불일치
- 실전에서는 @ManyToMany 사용X
@JoinColumn
*외래 키를 매핑 할 때 사용
*name - 매핑할 외래 키 이름(기본값은 테이블의 기본 키 컬럼명)
*referencedColumnName - 외래 키가 참조하는 대상 테이블의 컬럼명(참조하는 테이블의 기본 키 컬럼명)
*foreignKey(DDL) - 외래 키 제약조건을 직접 지정할 수 있다. 이 속성은 테이블을 생성할 때만 사용한다.
@ManyToOne
*다대일 관계 매핑
*optional - false로 설정하면 연관된 엔티티가 항상 있어야 한다.(기본값 TRUE)
*fetch - 글로벌 페치 전략을 설정한다(@ManyToOne = FetchType.EAGER, @OneToMany = FetchType.LAZY)
*cascade - 영속성 전이 기능을 사용한다.@OneToMany
*다대일 관계 매핑
*mappedBy - 연관관계의 주인 필드를 선택한다
*fetch - 글로벌 페치 전략을 설정한다.(@ManyToOne = FetchType.EAGER, @OneToMany = FetchType.LAZY)
*cascade - 영속성 전이 기능을 사용한다.
6. 상속관계 매핑
* 관계형 데이터베이스는 상속 관계X
* 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사
* 상속관계 매핑 : 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑
주요 어노테이션
@inheritance(strategy = InheritanceType.XXX)
- JOINED : 조인 전략
- SINGLE_TABLE : 단일 테이블 전략
- TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
@DiscriminatorColumn(name = "DTYPE")
@DiscriminatorValue("XXX")
@MappedSuperclass
- 공통 매핑 정보가 필요할 때 사용(id, name)
* 상속관계 매핑 X
* 엔티티X, 테이블과 매핑 X
* 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
* 조회, 검색 불가
* 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장
* @Entity 클래스는 엔티티나 @MappedSuperClass로 지정한 클래스만 상속 가능
페치 조인
fetch join
SQL 조인 종류 X
JPQL에서 성능 최적화를 위해 제공하는 기능
연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능
join fetch 명령어 사용
페치 조인 : = [LEFT[OUTER]| INNER] JOIN FETCH 조인경로
* 엔티티 페치 조인
* 회원을 조회하면서 연관된 팀도 함께 조회(SQL 한 번에)
* SQL을 보면 회원 뿐만 아니라 팀(T.*)도 함께 SELECT
* [JPQL] select m from Member m join fetch m.team
* [SQL] select M.*, T.* from Member m inner join team t ON M.team_ID = T.ID
`
String jpql = "select m from Member m join fetch m.team";
List
`
컬렉션 페치 조인
(일대다 관계, 컬렉션 페치 조인)[JPQL]
select t from Team t join fetch t.members where t.name = "팀A"아래와 같이 일대다 관계에서는 데이터가 뻥튀기 되어서 중복 결과를 반환해준다.
컬렉션 페치 조인 데이터 뻥튀기 해결 방안
* SQL의 DISTINCT 는 중복된 결과를 제거 * JPQL의 DISTINCT 2가지 기능 제공 1. SQL에 DISTINCT 를 추가 2. 애플리케이션에서 엔티티 중복 제거
****중요 : SQL에 DISTINCT 를 추가해도 데이터가 다르므로 SQL에서 중복 제거 실패
* DISTINCT 가 추가로 애플리케이션에서 중복 제거를 시도함.
* 같은 식별자를 가진 Team 엔티티 제거
페치 조인과 일반 조인의 차이
페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)
페치 조이은 객체 그래프를 SQL 한번에 조회하는 개념
페치 조인의 특징과 한계
페치 조인 대상에는 별칭을 못 준다.
둘 이상의 컬렉션은 페치 조인 불가능.
컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없다.
일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인해도 페이징 기능
하이버네이트는 경고 로그를 남기고 메모리에서 페이징
연관된 엔티티들을 SQL 한 번 으로 조회 - 성능 최적화
엔티티에 직접 적용하는 글로벌 로딩 전략 @OneToMany(fetch = FetchType.LAZY)보다 우선함
실무에서 글로벌 로딩 전략은 모두 지연 로딩
페치 조인 - 정리
여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야하면,
페치조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적
벌크 연산
JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
- 변경된 데이터가 100건 이라면 100번의 UPDATE SQL실행
executeUpdate()의 결과는 영향받은 엔티티 수 반환
UPDATE, DELETE 지원
String qlString = "update Member m set m.age = 20" int result = em.createQuery(qlString, Member.class) .executeUpdate();
벌크 연산 주의
* 중요
* 벌크 연산 수행 후 영속성 컨텍스트 초기화
em.clear();
기본 키 전략
@id
: 현재 필드가 기본키임을 알리기 위한 어노테이션@GeneratedValue
: 기본키 값 생성에 관련된 어노테이션@id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@GeneratedValue
- 기본 키 값을 자동생성하는 어노테이션으로 여러가지 전략이 있다.
IDENTITY
: DB에 위임, 보통 Mysql 사용 시SEQUENCE
: DB의 시퀀스 오브젝트 사용, 보통 Oracle 사용 시TABLE
: 키 생성용 테이블을 사용AUTO
: 방언에 따라 자정 지정(default 전략)
IDENTITY
- 주로 MySQL사용시 선택하는 전략
- DB에게 알아서 증가하도록 위임하는 방법
(MySQL의auto increment
수행) - 주의할 점(매우 중요)
- JPA는 영속성 컨텍스트를 통해
transaction.commit
시점에 SQL이 실행 -> DB가 알아서 기본키 값을 증가시키려면 어디까지 번호가 생성된지 알아야하는데 JPA가 이렇게 동작하면 알수가 없다. - 그래서 JPA에서
IDENTITY
전략을 사용하면 영속화와 동시에 SQL이 실행되도록 설정되어 있다. em.persist()
하면 바로 SQL이 수행되고 DB 식별자 번호를 반환해서 다음 번호로 영속성 컨텍스트에 저장된다.
- JPA는 영속성 컨텍스트를 통해
SEQUENCE
- DB의 시퀀스 오브젝트를 사용한다.
- DB 시퀀스 란?
- 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트
Oracle
등에서 사용됨
@Entity /* SequenceGenerator로 Sequence를 생성 */ @SequenceGenerator( name = "MEMBER_SEQ_GENERATOR", sequenceName = "MEMBER_SEQ", // 매핑할 데이터베이스 시퀀스 이름 initialValue = 1, allocationSize = 1) public class Member { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR") // 만든 SequenceGenerator 연결 private Long id; }
1).
@SequenceGenerator
선언
: 제너레이터 이름 / 시퀀스 이름 / 속성 값을 설정2).
@GeneratedValue(...)
지정
:전략(strategy)를 SEQUENCE / generator를 위에서 만든 시퀀스 제너레이터 연결- 동작 원리
em.persist()
로 영속화되어 등록 될 때sequence number
가 몇까지 나왔는지 모르기 때문에sequence call
을 수행sequence call
로 알아온number
를 통해 pk로 등록 후 영속성 컨텍스트에 등록
- 주의할 점
- 매번
em.persist()
할 때 마다sequence call
을 하면 비효율적이다. 그래서 제공되는 옵션이allocationSize
이다.
- 기본값이 50이 가지는 의미는 50번호 만큼 미리 메모리에 할당 해두는 것
- 미리 50까지는 메모리에 저장해서 증가시키기 때문에 DB의
sequence number
는 51이 등록되어 있을 것 임 - 50번의 번호가 가득 찼을 때 다음
sequence number
를 알아내는sequence call
이 수행되어 나름 효율적인 구조를 가지게 된다.
- 기본 키 값을 자동생성하는 어노테이션으로 여러가지 전략이 있다.
Table
키를 생성하고 관리하는 테이블을 하나 만들어서 DB 시퀀스를 흉내
모든 DB에 대해 적용 가능
성능이 좋지 못해 실무에서 잘 사용되지는 않는다.
시퀀스처럼 동작하기 때문에 역시
영속성 컨텍스트
문제를 겪게 되고 시퀀스와 동일하게allocationSize
옵션으로 동작한다.@Entity @SequenceGenerator( name = "MEMBER_SEQ_GENERATOR", table = "MY_SEQUENCES", // 데이터베이스 이름 pkColumnValue = "MEMBER_SEQ", allocationSize = 1) public class Member { @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR") private Long id;
AUTO
Default로 설정되는 값
방언에 따라 위의 3가지 전략을 자동으로 지정
(Mysql 인지/ Oracle 인지)
권장하는 식별자 전략
기본키 제약조건을 만족
- not null
- 유일성과 최소성
- 불변성
권장하는 식별자 전략
(Long형) + (대체키) + (적절한 키생성 전략)
이용Long
형을 사용해야 하는 이유int
는 0을 사용해서 null 과 0의 구분이 애매해서 오류가 날 수 있음Integer
는 10억이 넘어가면 순환해서 오류가 날 수 있음- 그래서 Long 이 위 두 문제를 어느정도 해결
- 대체키 사용
- 랜덤값 / UUID 등 비지니스와 관계없는 값
- 적절한 키 생성 전략
IDENTITY
/SEQUENCE
추천
'JPA' 카테고리의 다른 글
[JPA] QueryDSL 기본 문법 알아보기 (0) | 2023.04.07 |
---|---|
[JPA] 영속성 컨텍스트 이해 및 정리 (0) | 2023.04.03 |
[JPA] Auditing, Projections, Pageable 이해하기 (0) | 2023.03.30 |
[Java] JPA 최적화(완벽 요약) (0) | 2023.03.30 |
[JAVA]JPA N+1 문제란?(해결방안) (0) | 2023.03.29 |
- Total
- Today
- Yesterday
- 비동기
- spring mvc
- thread
- 공간쿼리
- 데이터베이스
- jpa
- 인덱스
- 영속성 컨텍스트
- 다운로드
- 스프링
- db
- GIS
- jenkins
- mysql
- 쓰레드
- oauth2
- database
- DispatcherServlet
- lock
- Index
- R-Tree
- 논블로킹
- Excel
- spring
- spring boot
- 네트워크
- github
- TCP
- java
- Spring Security
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |