엔티티 매핑 - 객체와 관계형 데이터베이스 매핑(설계)하기(Object Relational Mapping)
엔티티 매핑
- 객체와 테이블 매핑: @Entity, @Table
- 필드와 컬럼 매핑: @Column
- 기본 키 매핑: @Id
- 연관관계 매핑: @ManyToOne,@JoinColumn
객체와 테이블 매핑
1. @Entity : JPA 관리, JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수
- 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)
- final 클래스, enum,interface,inner 클래스 사용 X
- 저장할 필드에 final 사용 X -> final 사용시 값 변경 불가능하므로
2. @Table : 엔티티와 매핑할 테이블 사용
//데이터베이스 MBR이랑 매핑
@Table(name ="MBR")
데이터베이스 스키마 자동생성
<property name="hibernate.hbm2ddl.auto" value="create" />
1. DDL 자동 생성 : 애플리케이션 실행 시점에 프레임워크가 객체모델(엔티티 클래스 등)을 분석하여, 데이터베이스에 해당하는 테이블 생성, 변경을 위한 DDL 자동 생성
2. 객체 중심의 설계 : 개발자가 객체(클래스)를 작성하면, ORM 프레임워크가 이를 기반으로 데이터베이스 테이블을 자동으로 생성하거나 매핑
3. 데이터베이스의 방언 사용⭐️ : 다양한 데이터베이스의 SQL 문법 차이를 해결하기 위해 프레임 워크는 데이터 베이스 방언 사용하여 적합한 DDL 생성
4. 생성된 DDL은 개발 장비에서만 사용 : 생성된 DDL은 주로 개발 환경이나 테스트 환경에서만 사용. 개발 단게에서 데이터베이스의 구조를 빠르게 반영하고 수정하도록 도움을 줌.
5. 운영된 서버에서의 사용 : 생성된 DDL은 운영서버에서는 사용하지 않고, 필요시 이를 적절히 다듬은 후에 사용
옵션 | 설명 |
create
|
기존테이블 삭제 후 다시 생성 (DROP + CREATE)
|
create-drop
|
create와 같으나 종료시점에 테이블 DROP
|
update
|
변경분만 반영(운영DB에는 사용하면 안됨) -> DROP 하고 싶지 않은 경우.
|
validate
|
엔티티와 테이블이 정상 매핑되었는지만 확인
|
none
|
사용하지 않음
|
예시. age 추가하고 실행시
@Entity
public class Member
{
@Id
private Long id;
private String name;
private int age; //age 추가
}
데이터베이스 스키마 자동 생성 시 주의
- 운영장비에서는 절대 create, create-drop,update 사용하면 안된다.
- 개발 초기단계는 create or update
- 테스트 서버는 update or validate
- 스테이징과 운영 서버는 validate or none
DDL 생성 기능 : 데이터베이스 테이블을 자동으로 생성할 때 사용하는 설정
- 제약조건 추가: 회원 이름은 필수, 10자 초과X라고 추가 가능
-
@Column(nullable = false, length = 10) private String name;
- 유니크 제약조건 추가
-
@Table(uniqueConstraints = {@UniqueConstraint( name = "NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"} )})
- 실행 로직에서는 데이터베이스와 상호작용할 때 이미 존재하는 제약 조건을 인식하고 준수하지만, DDL 생성을 통해 추가된 제약 조건 자체가 JPA의 로직을 변경하거나 관여하지는 않습니다.
필드와 컬럼 매핑
어노테이션
|
설명
|
@Column
|
컬럼 매핑
|
@Temporal
|
날짜 타입 매핑
|
@Enumerated
|
enum 타입 매핑
|
@Lob
|
BLOB, CLOB 매핑
|
@Transient
|
특정 필드를 컬럼에 매핑하지 않음(매핑 무시) -> 메모리에서만 사용하기 위해서
|
‼️ @Column⭐️
속성
|
설명
|
기본값
|
name
|
필드와 매핑할 테이블의 컬럼 이름
|
객체의 필드 이름
|
insertable, updatable
|
등록, 변경 가능 여부
|
TRUE
|
nullable(DDL)
|
null 값의 허용 여부를 설정
false로 설정 = DDL 생성 시에 not null 제약조건 |
|
unique(DDL)
|
unique 속성은 한 컬럼에 유니크 제약조건을 걸 수 있지만, 컬럼에 사용된 제약조건의 이름이 시스템에 의해 자동으로 설정.-> 관리가 어려움 따라서 @Table의 uniqueContstrains 속성을 사용( 제약조건 이름을 명확하게 지정 가능.) |
|
columnDefinition (DDL)
|
데이터베이스 컬럼 정보를 직접 줄 수 있다.
ex) varchar(100) default ‘EMPTY'
|
필드의 자바 타입과 방언 정보를 사용해
|
length(DDL)
|
문자 길이 제약조건, String 타입에만 사용한다.
|
서 적절한 컬럼 타입
255 |
precision, scale(DDL)
|
아주 큰 숫자, 소수점에서 사용
BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다). precision은 소수점을 포함한 전체 자 릿수를, scale은 소수의 자릿수 다. 참고로 double, float 타입에는 적용되지 않는다. 아주 큰 숫자나 정 밀한 소수를 다루어야 할 때만 사용한다. |
precision=19, scale=2
|
@Enumerated⭐️
- EnumType.ORDINAL: enum 순서를 데이터베이스에 저장 -> 기본으로 사용하면 문제가 생길 수 있음(버그 에러)‼️
- EnumType.STRING: enum 이름을 데이터베이스에 저장 -> 필수로 써야한닥도 생각하기
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Enumerated
private RoleType roleType;
@Temporal
- 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
- 참고: LocalDate, LocalDateTime을 사용할 때는 생략 가능(최신 하이버네이트 지원) -> 이제 사라짐
@Lob
- 데이터베이스 BLOB, CLOB 타입과 매핑
기본 키 매핑
- 직접 할당 : @Id
- 자동 생성 : @GeneratedValue
- IDENTITY: 데이터베이스에 위임, MYSQL
- SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용, ORACLE - @SequenceGenerator 필요
- TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용 - @TableGenerator 필요
- AUTO: 방언에 따라 자동 지정, 기본값( IDENTITY, SEQUENCE, TABLE 중 하나 자동 선택 )
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;
1. IDENTITY 전략
- em.persist() 시점에 즉시 INSERT 쿼리가 실행
- 이로 인해 ID 값을 바로 알 수 있다.
- em.persist(entity); // INSERT 쿼리가 즉시 실행됨
- System.out.println(entity.getId());// ID 값을 알 수 있음 (DB에서 생성된 값)
- IDENTITY 전략은 INSERT 후에야 ID를 알 수 있으므로, 애플리케이션은 한 번에 여러 INSERT를 묶어 실행할 수 없다.(Batch Insert 불가능)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
2. SEQUENCE
- em.persist() 를 호출하면 JPA가 시퀀스 값을 미리 조회하여 엔티티 ID 할당
- SEQUENCE 전략에서 ID 값을 알 수 있는 이유는 em.persist() 호출 시 JPA가 시퀀스를 통해 ID 값을 미리 생성하고, 이를 엔티티에 할당한 뒤 영속성 컨텍스트에 저장하기 때문
- em.persist() //실행시 바로 System.out.println(entity.getId()) ID 값을 알 수 있다.
- INSERT 는 flush() 호출 또는 트랜잭션이 커밋될때 호출되므로 Batch Insert 가능
- 하지만 해당 부분을 그냥 사용 시에는 em.persist() 호출 시마다 SELECT 쿼리를 실행하기 때문에 데이터베이스와 통신하여 SELECT 쿼리를 실행하므로 성능 문제가 발생⭐️ => allocationSize 설정
- allocationSize를 50으로 설정하면, 한 번의 시퀀스 호출로 50개의 ID를 미리 가져옴.
- 50개의 엔티티를 삽입할 때 추가로 시퀀스 값을 조회
// PK 매핑
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id; // ID 타입은 Intege는 애매함..->Long 사용
2-1.@SequenceGenerator 사용
속성 | 설명 | 기본값 |
name
|
식별자 생성기 이름
|
필수
|
sequenceName
|
데이터베이스에 등록되어 있는 시퀀스 이름
|
hibernate_sequence
|
initialValue
|
(성능 최적화를 위해 사용) DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는 수를 지정한다.
|
1
|
allocationSize
|
(성능 최적화를 위해 사용) 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다
|
50
|
catalog, schema
|
데이터베이스 catalog, schema 이름
|
@Entity
@SequenceGenerator(
name ="member_seq_generator",
sequenceName ="member_seq")
public class Member
{
// PK 매핑
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_seq_generator")
private Long id; // ID 타입은 Long으로 변경
3. TABLE
데이터베이스에서 키 생성용 테이블을 별도로 만들어 기본 키를 생성하는 방법(단점 : 성능 최적화 문제점 존재)
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "MEMBER_SEQ", allocationSize = 1)
public class Member
{
// PK 매핑
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR")
private Long id; // ID 타입은 Long으로 변경
권장하는 식별자 조건
기본키 : null X, 유일(Unique), 변하면 X(Immutable)
=> 비즈니스 데이터는 변경될 가능성이 있으므로, 이를 기본키로 사용하면 데이터베이스의 무결성과 애플리케이션 로직에 영향을 미칠수 있으므로 비즈니스와 상관없는 값을 사용할 것
Long형 + 대체키 + 키 생성전략 사용(AUTO, SEQUENCE 사용) ⭐️
'Study Platform📚 > 김영한👨🏻🏫의 스프링 부트와 JPA 실무 완전 정복 로드맵' 카테고리의 다른 글
연관관계 매핑 기초 (0) | 2024.11.25 |
---|---|
영속성 관리 - 내부동작 방식 (0) | 2024.11.04 |
Hello JPA - 애플리케이션 개발 (1) | 2024.10.24 |
자바 ORM 표준 JPA 프로그래밍 - JPA 시작하기(맞는 버전 찾기) (1) | 2024.10.23 |