반응형
본 포스트는 사내 스터디로 진행되는 자바 ORM 표준 JPA 프로그래밍 관련 정리입니다
인프런 강의도 있습니다! 짱짱
https://www.inflearn.com/course/ORM-JPA-Basic
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔
www.inflearn.com
4장. 엔티티 매핑
- 매핑 정보는 XML, 어노테이션 중에 선택해서 기술 하면 된다
- 각기 장단점이 있지만, 어노테이션을 사용하는 쪽이 좀 더 쉽고 직관적이다
분류 | 어노테이션 |
객체와 테이블 매핑 | @Entity @Table |
기본 키 매핑 | @Id |
필드와 컬럼 매핑 | @Column |
연관관계 매핑 | @ManyToOne @JoinColumn |
4-1. @Entity
- JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야한다
@Entity 속성 | 설명 | 기본값 |
name | JPA에서 사용할 엔티티 이름을 지정 보통 기본값인 클래스 이름을 사용 |
설정하지 않으면 클래스 이름을 그대로 사용 |
- 기본 생성자는 필수 ( 최소 protected 이상의 생성자를 가져야 한다 )
- final, enum, interface, inner 클래스에는 사용할 수 없다
- 저장할 필드에 final을 사용하면 안된다
4-2. @Table
- 엔티티와 매핑할 테이블을 지정한다
- 생략시 매핑한 엔티티(@Entity) 이름을 테이블 이름으로 사용
@Table 속성 | 설명 | 기본값 |
name | 매핑할 테이블 이름 | 엔티티 이름을 사용한다 |
catalog | catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다 | |
scheme | schema 기능이 있는 데이터베이스에서 schema를 매핑한다 | |
uniqueConstraints(DDL) | DDL 생성 시에 유니크 제약조건을 만든다 스키마 자동 생성 기능을 사용해서 DDL을 만들때만 적용 |
4-3. 데이터베이스 스키마 자동 생성
- JPA는 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성할 수 있다
- 자동으로 생성되는 DDL은 데이터베이스 방언에 따라 달라진다
- 스키마 자동 생성 기능이 만든 DDL은 운영 환경에서 사용할 만큼 완벽하지는 않으므로 개발 환경에서 사용하거나 매핑 참고용 정도로 사용하는 것이 좋다
옵션 | 설명 |
create | 기존 테이블을 삭제하고 새로 생성한다 drop + create |
create-drop | create 속성에 추가로 어플리케이션을 종료시 생성한 DDL을 제거 drop + create + drop |
update | 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다 |
validate | 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 어플리케이션을 실행하지 않음 |
none | hibernate,hbm2ddl.auto 속성 자체를 유효하지 않은 옵션 값으로 설정 |
- 이름 매핑 전략 변경하기
- 단어와 단어를 구분할 때 자바는 관례상 카멜(Camel) 표기법을 주로 사용
- 데이터 베이스는 관례상 언더 스코어('_')를 주로 사용
- 방법
- 각 어노테이션(@Entity, @Table, @Column 등)의 name 속성에 명시적으로 데이터베이스 관련 이름을 지정해줄 수 있다
- hibernate.ejb.naming_strategy 속성을 사용해 이름 매핑 전략을 변경할 수 있다
4-4. DDL 생성 기능
- @Column 매핑 정보의 nullable 속성 값을 false로 지정하면 자동 생성되는 DDL에 not null 제약조건을 추가할 수 있다
- length 속성 값을 사용하면 자동 생성되는 DDL에 문자의 크기를 지정 할 수 있다 ( 기본값 255 )
- 위 기능들은 단지 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다
4-5. 기본 키 매핑
- 데이터베이스마다 기본 키를 생성하는 방식(오라클 시퀀스 오브젝트, MySQL AUTO_INCREMENT 등)이 다르므로 이 문제를 해결하기 위해 다양한 옵션을 제공한다
- JPA가 제공하는 데이터베이스 기본 키 생성 전략
- 직접 할당: 기본 키를 어플리케이션에 직접 할당 ( @Id )
- 자동 생성: 대리 키 사용 방식 ( @Id + @GeneratedValue )
- IDENTITY: 기본 키 생성을 데이터 베이스에 위임
- SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당
- TABLE: 키 생성 테이블을 사용
4-5-1. 기본 키 직접 할당 전략
- 기본 키를 직접 할당하려면 @Id 어노테이션만 사용하여 매핑하면 된다
- entityManager.persist()로 엔티티를 저장하기 전에 어플리케이션에서 기본 키를 직접 할당하는 방법
- 적용 가능 타입
- 자바 기본형 ( primitive type, [int, long, double....] )
- 자바 래퍼형 ( Wrapping type, [Integer, Long, Double.....] )
- String
- java.util.Date
- java.sql.Date
- java.math.BigDecimal
- java.math.BigInteger
- 기본 키 직접 할당 전략에서 식별자 값 없이 저장하면 예외가 발생, 어떤 예외가 발생하는지는 JPA 표준에 정의가 되지 않고 하이버네이트를 구현체로 사용하면 JPA 최상위 예외인 javax.persistence.PersistenceException 예외가 발생
4-5-2. IDENTITY 전략
- 기본 키 생성을 데이터베이스에 위임하는 전략
- 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다
- 데이터베이스에 값을 저장할 때 ID 컬럼을 비워두면 데이터베이스가 순서대로 값을 채워준다
( 즉 데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용 ) - 직접 할당이 아닌 경우 @GeneratedValue 어노테이션을 사용하고 식별자 생성 전략을 선택해야 한다
( @GeneratedValue(srategy=GenerationType.IDENTITY) ) - 엔티티가 영속 상태가 되려면 식별자가 반드시 필요하다
- IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 em.persist() 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다
- 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다
4-5-3. SEQUENCE 전략
- 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다
- 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용 가능
// Sequence Mapping
@Entity
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ",
initialValue = 1,
allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "BOARD_SEQ_GENERATOR")
private Long id;
....
}
- @SequenceGenerator를 사용해서 "BOARD_SEQ_GENERATOR"라는 시퀀스 생성기를 등록
- 속성 중 sequenceName의 이름으로 실제 데이터베이스의 시퀀스와 매핑한다
- @GeneratedValue 와 같이 @Id에 사용해도된다 ( Class단 말고 )
- 동작 방식
- em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회
- 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장
- 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장
- @SequenceGenerator
속성 설명 기본값 name 식별자 생성기 이름 필수 sequenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence initialValue DDL 생성 시에만 사용됨
시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정1 allocationSize 시퀀스 한 번 호출에 증가하는 수( 성능 최적화에 사용됨 ) 50 catalog, schema 데이터베이스 catalog, schema 이름 - SEQUENCE 전략과 최적화
- SEQUENCE 전략은 데이터베이스 시퀀스를 통해 식별자를 조회하는 추가 작업이 필요하기 때문에 2번의 통신이 필요
- 식별자를 구하려고 데이터베이스 시퀀스를 조회
- 조회한 시퀀스를 기본 키 값으로 사용해 데이터베이스에 저장
- JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocationSize를 사용한다
- allocationSize로 설정한 값만큼 한 번에 시퀀스 값을 증가시키고 나서 그만큼 메모리에 시퀀스 값을 할당한다
- 시퀀스 값을 어플리케이션 단에서 선점하므로 여러 JVM이 동시에 동작해도 기본 키 값이 충돌하지 않는다
- 시퀀스 값이 한번에 많이 증가한다는 단점은 존재
- SEQUENCE 전략은 데이터베이스 시퀀스를 통해 식별자를 조회하는 추가 작업이 필요하기 때문에 2번의 통신이 필요
4-5-4. TABLE 전략
- 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략
- 테이블을 사용하므로 모든 데이터베이스에 적용할 수 있다
// table mapping
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "BOARD_SEQ",
allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "BOARD_SEQ_GENERATOR")
private Long id;
....
}
- 시퀀스 대신 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 같다
- "MY_SEQUENCES" 테이블에 "BOARD_SEQ" 컬럼이 추가되고, 키 생성기를 사용할 때마다 해당 컬럼 값이 증가
- "BOARD"SEQ" 컬럼 값이 없다면 JPA가 INSERT하면서 초기화한다
- @TableGenerator
속성 기능 기본값 name 식별자 생성기 이름 필수 table 키 생성 테이블명 hibernate_sequences pkColumnName 시퀀스 컬럼명 sequence_name valueColumnName 시퀀스 값 컬럼명 next_val pkColumnValue 키로 사용할 값 이름 엔티티 이름 initialValue 초기 값
마지막으로 생성된 값이 기준0 allocationSize 시퀀스 한 번 호출에 증가하는 수
(성능 최적화에서 사용)50 catalog, schema 데이터베이스 catalog, schema 이름 uniqueConstraints(DDL) 유니크 제약 조건을 지정할 수 있다 - TABLE 전략은 값을 조회하면서 SELECT 쿼리를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용한다
TALBE 전략을 최적화하려면 SEQUENCE 전략과 마찬가지로 allocationSize를 사용하여 가능
4-5-5. AUTO 전략
- 선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다
- 예로 오라클은 SEQUENCE, MySQL은 IDENTITY를 사용한다
- @GeneratedValue의 strategy default 값
- 데이터베이스를 변경해도 코드를 수정할 필요가 없다는 장점이 있다 ( 아직 키 생성 전략이 정해지지 않았을 때 편리 )
4-5-6. 기본 키 매핑 정리
- 영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 영속 상태가 되려면 반드시 식별자 값(@Id)가 있어야 한다
- 권장하는 식별자 선택 전략
- 데이터베이스 기본 키는 다음 3가지 조건을 만족해야한다
- null 값은 허용하지 않는다
- 유일해야 한다
- 변해선 안된다
- 테이블의 기본 키를 선택하는 전략
- 자연 키: 비즈니스에 의미가 있는 키 ( 예: 주민등록번호, 이메일, 전화번호 등등 )
- 대리 키: 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불린다 ( 키 생성 테이블, auto_increment, 시퀀스 )
- 자연 키 보다는 대리 키를 권장한다
- 두 가지 다 장단점이 있지만, 비즈니스 로직과 연관된 자연 키를 사용할 경우 나중에 벌어질 상황에 대한 대처가 힘들다
- 현재는 물론이고 미래까지 충족하는 자연 키를 찾기는 쉽지 않다
- 대리 키는 비즈니스와 무관한 임의의 값이므로 요구사항이 변경되도 기본 키가 변경되는 일은 드물다
- 기본 키는 변하면 안 된다는 기본 원칙으로 인해, 저장된 엔티티의 기본 키가 변경되면 JPA는 예외를 발생시키거나 정상 동작을 하지 않는다 ( set method를 제공하지 않는 방식이 좋다 )
- 데이터베이스 기본 키는 다음 3가지 조건을 만족해야한다
4-6. 필드와 컬럼 매핑
분류 | 매핑 어노테이션 | 설명 |
필드와 컬럼 매핑 | @Column | 컬럼을 매핑한다 |
@Enumerated | 자바의 enum 타입을 매핑한다 | |
@Temporal | 날짜 타입을 매핑한다 | |
@Lob | BLOB, CLOB 타입을 매핑한다 | |
@Transient | 특정 필드를 데이터베이스에 매핑하지 않는다 | |
기타 | @Access | JPA가 엔티티에 접근하는 방식을 지정한다 |
4-6-1. @Column
- @Column은 객체 필드를 테이블 컬럼에 매핑한다
속성 | 기능 | 기본값 |
name | 필드와 매핑할 테이블의 컬럼 이름 | 객체의 필드 이름 |
insertable (거의 사용하지 않음) |
엔티티 저장 시 이 필드도 같이 저장한다 false로 설정시 해당 필드는 데이터베이스에 저장하지 않는다 false 옵션은 읽기 전용일 때 사용 |
true |
updatable (거의 사용하지 않음) |
엔티티 수정 시 해당 필드도 같이 수정 false로 설정시 데이터베이스에 수정하지 않는다 false 옵션은 읽기 전용일 때 사용 |
true |
table (거의 사용하지 않음) |
하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용 지정한 필드를 다른 테이블에 매핑할 수 있다 |
현재 클래스가 매핑된 테이블 |
nullable (DDL) |
null 값의 허용 여부를 설정한다 false로 설정시 not null 제약조건이 붙는다 |
true |
unique (DDL) |
@Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용 | |
columnDefinition (DDL) |
데이터베이스 컬럼 정보를 직접 줄 수 있다 | 필드의 자바 타입과 방언 정보를 사용, 적절한 컬럼 타입을 자동 생성 |
length (DDL) |
문자 길이 제약 조건, String 타입에만 해당 | 255 |
precision, scale(DDL) | BigDecimal 타입(BigInteger도 가능)에서 사용 precision은 소수점을 포함한 전체 자릿수 scale은 소수의 자릿수 double, float 타입에는 적용되지 않는다 |
precision=19, scale=2 |
- nullable
# nullable // java @Column(nullable = false) private String data; // SQL data varchar(255) not null
- unique
// unique // java @Column(unique = true) private String username; // SQL alter table tableName add constraint UK_Xxx unique (username)
- columnDefinition(DDL 생성 기능)
// columnDefinition // java @Column(columnDefinition="varchar(100) default 'EMPTY'") private String data; // SQL data varchar(100) default 'EMPTY'
- length(DDL 생성 기능)
// length // java @Column(length = 400) private String data; // SQL data varchar(400)
- precision, scale(DDL 생성 기능)
// precision, scale // java @Column(precision = 10, scale = 2) private BigDecimal cal; // SQL cal numeric(10,2) // h2, postgreSQL cal number(10,2) // oracle cal decimal(10,2) // MySQL
- @Column을 생략하게 되면?
- 대부분 @Column 속성들은 기본값(default)이 적용되는데 nullable 속성에는 예외가 있다
- @Column 속성을 생략 후 자바 기본 타입(primitive type)을 쓰게 되면 자동으로 not null 조건이 붙게 된다
- 단 @Column 속성 + 자바 기본 타입일 땐 nullable 속성의 기본값(true)로 동작
// nullable // #1 int data1; => data1 integer not null // #2 Integer data2; => data2 integer // #3 @Column int data3 => data3 integer
4-6-2. @Enumerated
- 자바의 enum 타입을 매핑할 때 사용
속성 | 분류 | 설명 | 기본값 |
value | EnumType.ORDINAL | enum 순서를 데이터베이스에 저장 | EnumType.ORDINAL |
EnumType.STRING | enum 이름(name)을 데이터베이스에 저장 |
- EnumType.ORDINAL
- 장점: 데이터베이스에 저장되는 데이터 크기가 작다
- 단점: 이미 저장된 enum의 순서를 변경할 수 없다
- EnumType.STRING
- 장점: 저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전하다
- 단점: 데이터베이스에 저장되는 데이터 크기가 ORDINAL에 비해서 크다
4-6-3. @Temporal
- 날짜 타입(java.util.Date, java.util.Calendar)를 매핑할 때 사용
- Spring Data JPA를 사용하고, java8이상을 쓴다면.. 잘 안쓸거 같다 ( LocalDateTime 사용 )
속성 | 분류 | 설명 | 기본값 |
value | TemporalType.DATE | 날짜, 데이터베이스 date 타입과 매핑 ( 2013-10-11 ) |
TemporalType은 필수로 명시적인 지정이 필요하다 |
TemporalType.TIME | 시간, 데이터베이스 time 타입과 매핑 ( 11:11:11 ) |
||
TemporalType.TIMESTAMP | 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 ( 2013-10-11 11:11:11 ) |
- 데이터 베이스 방언에 따라 생성되는 DDL
- datetime: MySQL
- timestamp: H2, 오라클, PostgreSQL
4-6-4. @Lob
- 데이터베이스 BLOB, CLOB 타입과 매핑
- @Lob에는 지정할 속성은 없고, 매핑하는 필드 타입에 따라 문자면 CLOB, 나머지는 BLOB으로 매핑한다
- CLOB
- String
- char[]
- java.sql.CLOB
- BLOB
- byte[]
- java.sql.BLOB
4-6-5. @Transient
- 이 필드는 매핑하지 않는다
- 데이터베이스에 저장하지 않고, 조회하지도 않는다
- 객체에 임시로 어떤 값을 보관하고 싶을 때 사용
4-6-6. @Access
- JPA가 엔티티 데이터에 접근하는 방식을 지정
- @Access를 설정하지 않으면 @Id 어노테이션의 위치를 기준으로 접근 방식이 설정된다
- 필드 접근
- AccessType.FIELD
- 필드에 직접 접근
- 필드 접근 지정자가 private이어도 접근할 수 있다
- 프로퍼티 접근
- AccessType.PROPERTY
- 접근자(getter method)를 사용
728x90
반응형
'Study > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
6장. 다양한 연관관계 매핑 (0) | 2021.09.13 |
---|---|
5장. 연관관계 매핑 기초 (0) | 2021.09.04 |
3장. 영속성 관리 (0) | 2021.08.22 |
1장. JPA 소개 (0) | 2021.08.09 |