카테고리 없음

JPA (3) - 엔티티 매핑

now0204 2024. 1. 11. 12:10

 

 

1. 객체와 테이블 매핑 

 

1.1 Entity

 

@Entity : JPA가 관리, 테이블과 매핑할 클래스는 Entity 필수 

               - 기본 생성자 필수, final클래스, enum, interface, inner클래스에는 사용불가 

               - 저장할 필드에 final 금지 

 

Entity 속성 : name : JPA에서 사용할 엔티티 이름 지정 (기본값은 클래스 이름 그대로 -> 가급적 기본값 사용하자)

 

1.2 @Table

 

엔티티와 매핑할 테이블 지정 

 

속성 : name : 매핑할 테이블 명 (기본값 엔티티 이름을 사용)

          catalog : DB catalog 매핑

          schema : DB scchema매핑 

          uniqueConstraints: DDL 생성 시 유니크 제약 조건 생성 

 

* 앞으로 나올 DDL 속성은 테이블 생성시 한번만 사용됨

 

2. 데이터 베이스 스키마 자동 생성 

 

- DDL은 실행 시점에 자동 생성 

- DB 방언 활용해서 적절한 DDL 생성

- 위 DDL은 개발 장비에서만 사용하자! (약간 오류 있을 수 있어서 그대로 반영 x)

 

속성

> xml에 hibernate.hbm2ddl.auto에 적을 값임

 

> create : 기본 테이블 삭제 후 다시 생성 (DROP + CREATE)

> create-drop : create와 같으나 종료 시점에 테이블 DROP (테스트 후에 다 날려버리고 싶을 때)

> update : 변경만 반영 (운영DB에서 사용 금지)

> validate : 엔티티와 테이블 정상 매핑되었는지 확인 

> none : 사용하지 않음 

 

* 운영 장비에는 절대 create, create-frop, update 사용금지 -> validate정도만 사용하자 

 

2.1 DDL 생성기능 

 

제약조건 추가: @Column(nullable = false, length = 10)

유니크 제약조선 추가 : @Table(uniqueConstraints = {@UniqueConstraint(name = "NAME_AGE_UNIQUE", columnNames = {"", ""})}

 

*생성에만 영향 실행로직에 영향없음 

 

 

3. 필드와 컬럼 매핑

 

ex) 요구사항 

1. 회원은 일반, 관리자

2. 회원 가입과 수정일 필요 

3. 회원을 설명할 수 있는 필드 -> 길이 제한 없음

 

@Entity
public class Member{


	@Id 
    private Long id;
    
    @Cloumn(name="name") //컬럼 매핑
    private String username;
    
    private Integer age;
    
    @Enumerated(EnumType.STRING) //enum타입 매핑
    private RoleType 
    
    @Remporal(TemporalType.TIMESTAMP) //날짜매핑 -> JAVA 8부터는 LocalDateTime있어서 안쓴다함
    private Date createdDate;
    
    @Remporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
    
    @Lob //BLOC,CLOB매핑 
    private String desciption;
    
    //@Transinet : 필드를 컬럼에 매핑 안함

}

 

 

3.1 Column 속성

 

name : 필드와 매핑할 테이블 칼럼 명  (기본 값 객체의 필드명)

insertable,updatable : 등록 및 변경 가능 여부

unllable(DDL) : null값 허용 여부 

unique(DDL) : 유니크 제약조건 -> 근데 테이블에서 사용하는게 나음 

columnDefinition(DDL) : DB 컬럼 정보를 직접 줄 수 있다. (필드의 자바 타입과 방언 정보 활용해서 넘김)

length(DDL) : 문자 길이 제약조건 

percisionscale(DDL) : BigDecimal 타입에서 사용 (BigInteger) percision은 소수점 제외한 전체 자릴수, scale은 소수의 자릿수 (double, float타입에는 적용x 아주 큰 숫자 혹은 정밀한 소수 다룰 때 사용)

 

3.2 @Enuerated

 

> value를 STRING으로 사용하자 무조건 (기본값은 ORDINAL임)

 

3.3 @Lob

 

CLOB : String, char[], java.sql.CLOB

BLOB : byte[], java.sql.BLOB

 

3.4 Transient 

 

> 메모리 상에서만 임시로 보관하고 싶은 값만 저장

 

4. 기본키 매핑 

 

@Id 직접할당 , @GeneratedValue (자동생성) 사용한다.

 

4.1GeneratedValue 

 

IDENTITY : 데이터 베이스에 위임한다. MYSQL

SEQUENCE : 데이터 베이스에 시퀀스 오브젝트 사용한다 (@SequenceGenerator 필요) ,ORACLE

TABLE : 키 생성용 테이블 지정 (모든 DB에서 사용가능 @TableGenerator 필요 

AUTO: 방언에 따라 자동 지정 (기본값)

 

 

- IDENTITY 전략 

 >주로 MySQL, PostgreSQL, SQL Server에서 사용 (AUTO_INCREMENT)

 > JPA는 트랜잭션 커밋 시점에 INSERT SQL 실행

 > IDENTITY 전략은 em.persist()시점에 즉시 INSERT SQL 실행한다 (식별자 조회해야해서)

 

* 영속성 컨텍스트에 보관되는 동안 기본키 값을 알아야 관리가능 DB에 이를 위임했으면, DB에 다녀와야해서...

 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 

- SEQUENCE 전략

 

> 오라클, PostgreSQL, DB2, H2에서 사용함 

> DB에 시퀀스를 미리 불러와서 하나씩 쓰다가 시퀀시 범위 넘어가면 다시 받아옴 

 

@SequenceGenerator(

	name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ" // 매핑할 데이터 베이스 시퀀스 명
    initialValue = 1 , allocationSize = 1)
)

public class Member {

	@Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")
    private Long id;
}

 

- name: 식별자 생성기 이름 

- sequenceName : DB에 등록된 시퀀스명 (기본값은 하이버네이트의 시퀀스)

- initialValue : DDL 생성시에만 사용 -> 시퀀스 생성할 때 처음 1로 시작하는 수 지정 

- allocationSize : 시퀀스 한번 호출시 증가하는 수(최적화에 사용된다. ) DB 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 사용한다 (기본값은 50이다)

 

*allocatotionSize는 한 트랜잭션 내에서 시퀀스 한번에 몇개씩 불러와서 사용할지 지정하는 것 

따라서 크게 잡으면 DB접근횟수가 줄어들어서 좋은점은 있지만, 

(기본값 50일때)  만약 트랜잭션1에서 저장하고 트랜잭션2에서 다시 저장하려고 부르면 -> 트랜잭션 2의 기본키는 51부터 시작함! 

 

- TABLE 전략

 

 > 키 생성 전용 테이블을 만들어서 시퀀스 흉내내기 

> 모든 DB에서 사용가능하지만, 성능이 딸림 

 

@TableGenerator(
	name = "GNETO",
    table = "MY_SEQ",
    pkColumnValue = "MEMBER_SEQ", allocationSize =1 )
)

public class Member{
	
    @Id
    @GenratedValue(strategy = GenerationType.TABLE, generator = "GNETO")
    private Long id;

}

 

- pkColumnName: 시퀀스 테이블에 pk 컬럼명 (기본 sequence_name)

- valueColumnName : 시퀀스 값 컬럼명 (기본 next_val)

- pkColumnValue : 키로 사용할 값 이름 (기본 값 엔티티 명) 

- uniqueConstraints(DDL) : 유니크 제약 조건 지정 가능 

 

 

> 권장하는 식별자 전략 

 

- 키본 키 제약 조건 : null 아님, 변화금지 

- 미래까지 이조건을 만족하는 자연키 찾기 어렵다 대리키 사용하자 

- 권장 : LONG형 + 대체키 + 키 생성전략 사용 

* ai 나 시퀀스 object 사용하자 -> 때에 따라 uuid  (비지니스를 키로 끌고 오는 것은 권장하지 않음)

 

 

 

*column에 length같은 건 남기는 걸 선호 (개발자가 테이블 보고 유추가능)

  제약조건은 @Table등에 적자 

  부트 사용시 하이버네이트 이름 전략 (관례) 직접 바꿀 수 있다!

 

*이제 연관관계를 배워서 객체 설계를 테이블에 맞춘게 아니라, 그래프 탐색이 가능하도록 연관관계 매핑해보자