-
JPA (3) - 엔티티 매핑카테고리 없음 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등에 적자
부트 사용시 하이버네이트 이름 전략 (관례) 직접 바꿀 수 있다!
*이제 연관관계를 배워서 객체 설계를 테이블에 맞춘게 아니라, 그래프 탐색이 가능하도록 연관관계 매핑해보자