Spring/JPA

[JPA] 엔티티 매핑

김긍수 2021. 3. 6. 06:26

객체매핑 @Entity

@Entity가 붙은 클래스는 엔티티가 되고 JPA가 관리한다.

JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수이다.

@Entity 속성 : name

@Entity(name = " ")
  • JPA에서 사용할 엔티티 이름을 지정하는 것이다.
  • 디폴트 값은 현재 클래스 이름 그대로이다.
  • 같은 클래스 이름이 없으면 되도록 기본값을 사용하는 것이 좋다.

!!!주의!!!

  • @Entity가 붙은 클래스는 기본 생성자가 필수이다.

  • final 클래스, enum, interface, inner클래스를 사용할 수 없다.

  • 저장할 필드에 final을 사용할 수 없다.

테이블매핑 @Table

@Table은 엔티티와 매핑할 테이블을 지정하는 것이다.

@Table 속성 : name, catalog, schema, uniqueConstraints(DDL)

@Table(name = "DB테이블명")
  • 데이터베이스 상 테이블이름이 USER이고 코드상으로는 Member를 사용해야한다면, Member 클래스 위에 @Table(name = "DB테이블명") 작성해주면 해당 엔티티는 테이블과 맵핑이 된다.
catalog
  • 데이터베이스 catalog를 매핑한다.
schema
  • 데이터베이스 schema를 매핑한다.
uniqueConstraints 
  • DDL 생성 시에 유니크 제약 조건을 생성한다.

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

  • DDL을 애플리케이션 실행 시점에 자동 생성한다.
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.
  • 생성된 DDL은 개발장비에서만 사용하고 운영서버에서는 사용하지 않는다. (적절히 다듬은 후 사용)
<property name="hibernate.hbm2ddl.auto" value="속성값"/> // (persistence.xml) 
  1. create : 기존 테이블 삭제 후 다시 생성한다. (DROP + CREATE)
  2. create-drop : create와 같으나 종료시점에 테이블을 DROP한다.
  3. update : 변경된 부분만 반영한다. (운영DB에서는 사용하면 안된다)
  4. validate : 엔티티와 테이블이 정상매핑되었는지만 확인해준다.
  5. none : 사용하지 않음

DDL생성기능

제약조건 추가 : 회원이름은 필수, 5자 초과하면 안됨

  • @Column(nullable = false, length = 10)

유니크 제약조건 추가

  • @Table(uniqueConstraints = {@UniqueConstraint(name = "NAME_AGE_UNIQUE" columnNames = {"NAME", "AGE"})})

유니크 제약조건 : 중복된 값을 허락하지않는다.

 

필드매핑 @Column

@Column은 필드명과 DB 테이블 컬럼명을 맵핑시켜준다.

@Column(name = "DB컬럼명")
속성 설명 기본값
name 필드와 매핑할 테이블의 컬럼명을 작성하여 맵핑함. 객체의 필드 이름
insertable,
updatable
등록, 변경 가능 여부 true
nullable(DDL) null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.  
unique(DDL) @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다.  
columnDefinition(DDL) 데이터베이스 컬럼 정보를 직접 줄 수 있다.  
length(DDL) 문자 길이 제약조건, String타입에만 사용한다. 255
precision, scale(DDL) BigDecimal, BigInteger 타입에서 사용한다. precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수이다. 
*double, float타입에는 적용되지않는다. 
presision = 19,
scale = 2 

enum타입 매핑 @Enumerated

자바 enum 타입을 매핑할 때 사용한다.

@Enumerated 속성

@Enumerated(EnumType.STRING)

기본값은 EnumType.ORDINAL이다. 하지만 ORDINAL을 사용해선 안된다. 왜냐하면

예를 들어 enum클래스에 { 강아지, 고양이, 사자 }가 있다고 가정해보자.

지금까지 강아지를 저장하게 되면 0이 저장되어졌을 것이다. 하지만 enum클래스가 { 펭귄, 강아지, 고양이, 사자 } 로 변경된다면 펭귄이 0이 된다. 따라서 무조건 STRING으로 저장되어야한다.

 

날짜 타입 매핑 @Temporal

날짜타입을 매핑할 때 사용한다.

@Temporal 속성 

@Temporal(TemporalType.DATE) // 날짜, 데이터베이스 date타입과 매핑 (2021-03-06)
@Temporal(TemporalType.TIME) // 시간, 데이터베이스 time타입과 매핑 (02:30:11)
@Temporal(TemporalType.TIMESTAMP) // 날짜와 시간, 데이터베이스 timestamp타입과 매핑(2021-03-06 05:10:10)

하지만 최신 하이버네이트는 LocalDate, LocalDateTime을 지원한다. 이 두가지를 사용할 경우에는 생략이 가능하다.

BLOB, CLOB 매핑 @Lob

데이터베이스 BLOB, CLOB 타입과 매핑한다.

매핑하는 필드 타입이 문자면 CLOB 매핑이 되고, 나머지는 BLOB매핑이 된다.

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

BLOB : byte[], java.sql.BLOB

 

***Lob : LOB는 Text, 그래픽, 이미지, 비디오, 사운드 등 구조화되지 않은 대형 데이터를 저장하는데 사용한다.

일반적으로 테이블에 저장되는 구조화된 데이터들은 크기가 작지만, 멀티미디어 데이터는 크기가 크다.

크기가 큰 데이터는 DB에 저장하기 힘들기 때문에 운영체제에 존재하는 파일을 데이터베이스가 접근하게된다.

1. CLOB : 문자 대형 객체 (Character)

2. BLOB : 이진 대형 객체 (Binary) - 이미지, 동영상, MP3 등

특정 필드를 컬럼에 매핑하지 않음 (매핑 무시) @Transient

필드가 테이블 컬럼과 매핑되지 않고, 데이터베이스에 저장도 조회도 되지 않는다. 메모리상에서만 임시로 값을 보관하고 싶을 때 사용한다.

 

기본키매핑 @Id

직접할당 : @Id                   // 내가 직접 id를 셋팅하고 싶은 경우

자동생성 : @GeneratedValue(strategy = "") // 디폴트 GenerationType.AUTO

  • IDENTITY전략  : 데이터베이스에 위임, MYSQL 

기본 키 생성을 데이터베이스에게 위임한다. 주로 MySQL, postgresql, sql server, db2에서 사용한다.

(MySQL의 AUTO_INCREMENT) // id값을 null로 하면 db가 알아서 AUTO_INCREMENT해준다.

JPA는 트랜잭션 커밋 시점에 insert sql을 실행한다.

AUTO_INCREMENT는 데이터베이스에 insert sql을 실행한 이후에 id값을 알 수 있다.

em.persist() 시점에 즉시 insert sql을 실행하고 db에서 식별자를 조회한다.

 

**한가지 문제!

IDENTITY전략은 db에 들어가기 전까지 기본키인 id를 모르는데, 기본키가 필수로 필요한 영속성 컨텍스트에 넣을 방법이 없다. IDENTITY전략에서만 예외적으로 persist를 호출하자마자, db에 쿼리를 보낸다.

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

 

  • SEQUENCE 전략 : 데이터베이스 시퀀스 오브젝트 사용, ORACLE (@SequenceGenerator가 필요하다)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

//시퀀스에서 값을 가져온 다음 값을 세팅해서 db에 들어가게 된다. (기본시퀀스)

 

데이터베이스시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다.( 오라클의 시퀀스같음)

오라클, postgresql, db2, h2데이터베이스에서 사용한다.

@Entity
@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;
    
    // 이렇게 실행을 하게되면 MEMBER_SEQ라는 시퀀스를 생성함

 

  • TABLE 전략 : 키 생성용 테이블 사용, 데이터 베이스 시퀀스를 흉내내는 전략이다. 모든 DB에서 사용한다. (@TableGenerator 필요)

시퀀스 테이블이 생성되고, 시퀀스네임과 NEXT_VAL의 컬럼이 생성된다. //운영에서는 쓰기에는 조금 부담스러움

 

*** 시퀀스 관련 : persist()할때마다 쿼리를 보내므로 성능이 떨어진다. 이러한 성능 최적화를 위해서는 allocationSize를 사용하면 된다. 테이블의 시퀀스값을 미리 많이 올려놓고, 웹서버에서 그것을 사용함.

 

연관관계매핑 @ManyToOne, @JoinColumn

 

권장하는 식별자 전략

  • 기본 키 제약 조건 : null이 아니어야한다. 유일해야한다. 변하면 안된다.
  • 미래까지 이 기본키 제약 조건을 만족하는 자연키는 찾기 어렵다. 따라서 대체키(비즈니스와 상관없는)를 사용하자!
  • 주민등록번호도 기본키로 적절하지 않다. 법이 바뀌어서 주민번호도 저장하면 안되는 등 예상하지 못한 상황이 발생할 수 있다.
  • 권장하는 것은 Long형 + 대체키 + 키 생성전략을 사용하는 것이 좋다.