자라선

[자바 ORM 표쥰 JPA 프로그래밍] 8일차 - 테이블 초기화 및 기본키 전략 본문

Develop/JPA

[자바 ORM 표쥰 JPA 프로그래밍] 8일차 - 테이블 초기화 및 기본키 전략

자라선 2021. 8. 14. 02:18

1. 어노테이션

JPA는 자바 클래스 VO와 DB의 테이블을 매핑하기 위해 어노테이션 지원한다.

 

@Entity

JPA는 테이블 매핑을 하기위해서는 @Entity 어노테이션을 필수로 붙여야 한다.

JPA는 @Entity 어노테이션이 붙은 클래스를 DB 클래스와 매핑 시켜주기 때문인데

동시에 JPA는 식별자를 필수로 가지고있어야 영속 상태로 접근할 수 있기 때문에

@Id 라는 어노테이션도 최소 1개 이상 사용해야한다. (없으면 유효성 에러남)

 

@Table 어노테이션과 @Column 어노테이션으로 name 속성을 사용해 테이블과 매핑시킬 테이블명 및 컬럼명을 명시할 수 있다.

@Entity
@Table(name="MEMBER")
public class Member {

    @Id
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME")
    private String username;
    
    ... setter & getter

 

2. 테이블 초기화 전략

JPA는 개발 및 테스트 환경을 위해 수시로 변경되는 컬럼이나 테이블을 개발자가 CREATE, DROP, ALTER 할 필요 없이 자동으로 생성해주는데 이를 보고 테이블 초기화 전략이라 부른다.

 

적용방법은 JPA 설정 파일 persistence.xml 파일에 property 속성을 하나 추가해주면 된다.

<property name="hibernate.hbm2ddl.auto" value="create" />

value 종류는 다음과 같다.

value 설명
create 어플리케이션이 실행되면 테이블들 DROP 하고 CREATE 한다. (DROP -> CREATE)
create-drop 어플리케이션이 실행되면 테이블들 DROP 하고 CREATE 후 종료시 DROP 한다.
(DROP -> CREATE -> DROP)
update 데이터베이스 테이블과 엔티티 매핑 정보를 비교 후 변경 사항을 수정한다.
vaildate DB 테이블과 엔티티 매핑 정보 비교 후 변경 사항이 있으면 어플리케이션 종료한다.
none 테이블 초기화를 사용하지 않는다.

 

더보기

테이블 초기화 전략시 주의점 (서적에 있는 그대로 기술..)

- 개발 초기 단계는 create OR update

- 초기화 상태로 자동화된 테스트를 진행하는 개발자 환경과 CI 서버는 create OR create-drop

- 테스트 서버는 update OR vaildate

- 스테이징과 운영 서버는 vaildate OR none

 

DDL 제약 조건

    @Column(name = "NAME", nullable = false, length = 10) //추가 //**
    private String username;

컬럼에 null 가능 여부 및 길이를 제약을 추가할수 있다.

 

@Entity
@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint( //추가 //**
        name = "NAME_AGE_UNIQUE",
        columnNames = {"NAME", "AGE"} )})
public class Member {

테이블의 유니크 제약 조건을 추가 시 위 코드와 같은 양식으로 작성한다.

 

여기까지의 제약조건 어노테이션들은 DDL 초기화시 영향을 주지 기존 DB 테이블과는 관련없다.

 

3.  기본키(PK) 전략

JPA 는 테이블 초기화시 기본키(PK) 를 @Id 어노테이션을 사용해 추가하지만 기본키의 값을 자동으로 추가해주는 기능을 제공해준다.

마치 ORACLE의 SEQUENCE 나 MYSQL의 AUTO_INCREMENT 를 사용하게끔 하는데 DB 마다 사용하는 기능이 다르므로 각가 다른 설정을 해주어야한다.

 

직접 기본키값을 할당하는 방식이 아니라 다른 기본키 자동 생성 전략을 사용한다면 persistence.xml에 속성을 추가해야한다.

<property name="hibernate.id.new_generator_mappings" value="true" />

 

  • 직접 기본키 값을 할당하는 방법
    기존과 동일하게 별개의 설정해줄 필요 없이 setId(pk_number) 를 하여 INSERT 하는 방식

  • 기본키 생성을 DB에 위임하는 IDENTITY 
    DB가 MYSQL, POSTGRESQL, SQL SERVER, DB2 일 때 사용하는 방식이며,
    기본키 데이터 생성을 DB에 직접 할당한다.
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID")
        private int id;​
    설정은 엔티티 @Id 필드에 @GeneratedValue 를 추가하고 속성값을 IDENTITY 로 추가한다.

    이렇게 설정한 경우 엔티티는 영속 상태로 진입하기 위해서는 식별자를 가지고있어야하지만 기본키를 DB에서 부여해주기 때문에 영속상태로 받지 못한다. 그렇기 때문에 persist(엔티티) 를 호출하면 바로 INSERT SQL 이 DB로 전달되어 트랜잭션을 지원하는 쓰기 지연이 적용되지 않는다. (테이블에 데이터를 저장해야 식별자 값을 얻을 수 있다.)
    (추가) JPA는 INSERT 후 바로 기본키 값을 조회할 수있는데 JDBC3에 추가된 Statement.getGeneratedKeys() 메소드로 데이터를 저장하면서 동시에 기본키 값을 얻어오는데 하이버네이트는 이 메소드를 사용한다.

  • 테이블 초기화시 DB에 시퀀스를 생성하여 기본키에 할당하는 방식 SEQUENCE
    데이터베이스의 시퀀스를 추가하여 기본키에 적용하는 방식이다. 
    그러다보니 시퀀스가 있는 ORACLE, POSTGRESQL, DB2, H2 등 DB에서 사용할 수가 있다.
        @Id
        @SequenceGenerator(
                name = "MEMBER_SEQ_GENERATOR",
                sequenceName = "MEMBER_SEQ",
                initialValue = 1,
                allocationSize = 1
        )
        @GeneratedValue(strategy = GenerationType.SEQUENCE
                     , generator = "MEMBER_SEQ_GENERATOR")
        @Column(name = "ID")
        private int id;​
     설정은 컬럼이나 클래스단에 @SequenceGenerator 를 추가하여 시퀀스를 생성 후  @GeneratedValue 에서 생성한 시퀀스와 연동시키면 된다.

    DB에서 시퀀스 값을 SELECT 후 받아온 값을 엔티티에 넣어 영속성 컨텍스트에 저장 후 INSERT를 수행한다.

    한가지 주의할점은 시퀀스를 생성할때 allocationSize를 1로 명시하였는데 따로 명시하지 않는다면 JPA는 기본값을 50으로 설정한다. 이 값은 시퀀스를 호출할때 마다 값이 50씩 증가하게 되는데 나중에 시퀀스를 DB상에서 관리하게 된다면 문제가 발생할 수 도 있기때문에 주의해야한다.

  • 테이블을 생성하여 키 생성 테이블로 사용하는 TABLE
    MYSQL의 AUTO_INCREMENT 기능이나 ORACLE의 SEQUENCE 가 없는 DB의 경우 사용할 수있는 방법으로 시퀀스용 테이블을 자동생성하여 시퀀스 처럼 사용한다.
        @Id
        @TableGenerator(
                name = "MEMBER_SEQ_GENERATOR",
                table = "MY_SEQUENCES",
                pkColumnValue = "MEMBER_SEQ",
                allocationSize = 1
        )
        @GeneratedValue(strategy = GenerationType.TABLE
                     , generator = "MEMBER_SEQ_GENERATOR")
        @Column(name = "ID")
        private int id;​
     
    시퀀스와 비슷하나 @TableGenerator 어노테이션으로 사용하였다.
    자동 생성된 시퀀스 테이블
    정말 테이블을 하나 생성하였기 때문에 테이블을 SELECT 또한 가능하며 시퀀스 처럼 사용하기 때문에 value 값은 JPA가 자동으로 UPDATE 하여 가산해준다. 

  • Default @GeneratedValue 방식 AUTO
    @GeneratedValue 어노테이션을 정의해주었으나 별도의 GenerationType를 명시해주지 않는다면 AUTO 로 생성되어 JPA가 접속한 DB에 맞게 자동으로 IDENTITY, SEQUENCE, TABLE 전략중 하나를 선택하여 가산해준다. 
        @Id
        @GeneratedValue
        @Column(name = "ID")
        private int id;

Comments