반응형

객체와 테이블 매핑

@Entity

  • 선언된 클래스는 JPA가 관리한다. 엔티티라 한다.
  • 기본 생성자가 반드시 있어야한다.
    • JPA 내부적으로 사용한다. (접근제한 설정은 public 또는 protected 가능)
  • final 클래스, enum, interface, inner 클래스에는 @Entity를 사용할 수 없다.
  • 저장할 필드에 final 키워드를 사용하면 안된다.
  • @Entity 속성
    • name
      • JPA에서 사용할 엔티티 이름을 지정한다.
      • 기본 설정은 클래스 이름을 그대로 사용한다.
        • Member 클래스위에 선언한 경우 Member
      • 같은 클래스 이름이 없으면 가급적 기본 값을 사용한다.

 

@Table

  • 엔티티와 매핑할 테이블을 지정한다.
  • @Table 속성
    • name
      • 매핑할 테이블 이름.
      • 기본 설정은 엔티티 이름을 사용한다.
    • catalog
      • 데이터베이스 catalog 매핑
    • schema
      • 데이터베이스 schema 매핑
    • uniqueConstraints
      • DDL 생성 시에 유니크 제약 조건 생성
  • 예) 유니크 제약조건 추가(DDL 생성 기능)
    • @Table(uniqueConstraints = {@UniqueConstraint( name = “NAME_AGE_UNIQUE”, columnNames = {”NAME”, “AGE”})})

 

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

  • JPA는 애플리케이션 실행 시점에 DDL을 자동 생성하는 기능을 지원한다.
  • DDL 생성 기능은 DDL을 자동생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성해준다.
  • 생성된 DDL은 개발환경, 로컬환경에서 테스트용으로 사용할 수 있다.
  • 운영에서 사용하려면 생성된 DDL을 더 다듬어서 사용해야 한다.
  • hibernate.hbm2ddl.auto 옵션
    • create
      • 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
    • create-drop
      • create와 같으나 종료시점에 테이블 DROP한다.
    • update
      • 추가되는 변경 부분만 반영(운영DB에는 사용하면 안된다)
      • alter table
      • 기존 컬럼을 삭제하는 것은 DDL이 생성되지 않는다.
    • validate
      • 엔티티와 테이블이 정상 매핑되었는지만 확인한다.
      • 정상적으로 매핑되지 않은 경우 에러 발생한다.
    • none
      • DDL 자동 생성 기능을 사용하지 않는다.
      • 이 옵션은 실질적으로 존재하지 않는다.
        • JPA가 인식할 수 없음, 옵션에 해당하지 않는 문자를 입력한 것과 마찬가지이다.
      • 관례상 옵션을 사용안하는 것을 none을 적어서 표현하기도 하며 주석 처리를 하기도 한다.

스키마 자동 생성 옵션 주의점

  • 운영환경에서는 절대 create, create-drop, update를 사용하면 안된다.
  • 개발 초기 단계는 create 또는 update
  • 테스트 서버는 update 또는 validate
  • 스테이징과 운영서버는 validate 또는 none
  • 가장 권장하는 것은 DDL 스크립트를 만들어서 DB에 직접 적용하는 것이 좋다.
  • 운영환경에서 drop, alter를 모든 개발자가 마음대로 할 수 없도록 권한을 분리하여 계정별로 운영, 관리하는 것 또한 중요하다.

 

필드와 컬럼 매핑

@Column

  • 컬럼을 매핑할 떄 사용한다.
  • name
    • 객체의 필드와 매핑할 테이블의 컬럼이름을 매핑하는 데 사용한다. 기본값은 객체의 필드 이름으로 설정되어 동작한다.
    • 객체 필드명과 DB 컬럼명이 다른 경우, 객체 필드명을 DB컬럼명으로 인식하도록 매칭시킬 수 있다.
  • insertable
    • 컬럼 등록 가능 여부. 기본 값은 TRUE
    • 등록할 때 쿼리에 이 컬럼을 포함할 것인가 안할 것인가에 대한 것이다.
  • updateable
    • 컬럼 변경 가능 여부. 기본 값은 TRUE
    • 수정할 때 쿼리에 이 컬럼을 포함할 것인가 안할 것인가에 대한 것이다.
  • (DDL)length
    • DDL과 관련된 속성이다.
    • 문자 길이 제약조건, String 타입에만 사용한다. 기본 값은 255 이다.
  • (DDL)nullable
    • DDL과 관련된 속성이다.
    • null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.
    • 예) 제약조건 추가: 회원 이름은 필수, 10자 초과 불가능(DDL 생성 기능)
      • @Column(nullable = false, length = 10)
  • (DDL)unique
    • DDL과 관련된 속성이다.
    • @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다.
    • 잘 사용하지는 않는다. 제약조건 이름이 이상하게 생성된다. 또한 여러 컬럼에 대해서 unique 제약조건을 걸 수 없다.
    • @Table 의uniqueConstraints 는 제약조건 이름까지 설정할 수 있고 여러 컬럼에 대해서도 제약조건을 걸 수 있어서 @Table 의uniqueConstraints 를 사용하는 것이 좋다.
  • (DDL)columnDefinition
    • DDL과 관련된 속성이다.
    • 데이터베이스 컬럼 정보를 직접 설정해줄 수 있다.
    • 예) 컬럼의 길이를 100으로 하고 컬럼의 기본 값으로 EMPTY 라고 설정한다.
      • @Column(columnDefinition = "varchar(100) default 'EMPTY'")
  • precision, (DDL)scale
    • BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다).
    • precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다.
    • 참고로 double, float 타입에는 적용되지 않는다.
    • 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
    • 기본값
      • precision=19
      • scale=2

 

@Enumerated

  • enum 타입을 매핑하기 위해서 사용한다.
  • 일반적으로 DB에는 enum 타입이 존재하지 않기 때문에 enum 타입은 이를 사용해서 매핑해야한다.
  • value
    • EnumType.ORDINAL
      • enum 순서를 데이터베이스에 저장. 기본 값으로 설정되어 있다.
      • 숫자 타입으로 저장된다.
    • EnumType.STRING
      • enum 이름을 데이터베이스에 저장.
      • 문자 타입으로 저장된다.
  • 기본값은 EnumType.ORDINAL 이다. 그러나 절대로 EnumType.ORDINAL 를 사용하면 안된다.
  • 첫 번째 또는 중간에 EnumType이 추가되는 경우, enum 타입의 순서가 변경되어 기존 데이터가 가지는 순서가 모두 영향을 받아서 엉뚱한 데이터가 조회되고 사용되는 상황이 발생한다.
  • 따라서 enum 타입을 사용하는 경우에는 반드시 값을 EnumType.STRING 로 설정하여 사용해야 한다.

 

@Temporal

  • 날짜 타입(java.util.Date, java.util.Calendar)을 매핑하기 위해서 사용한다.
  • 단, LocalDate(년월일), LocalDateTime(년월일시)을 사용할 때는 생략 가능하다.
    • 최신 하이버네이트에서 지원한다.
  • 자바에서는 날짜 타입에 날짜와 시간이 모두 존재한다.
  • DB에서는 날짜, 시간, 위치 이런 것들을 모두 구분해서 사용하기 때문에 어떤 방식으로 날짜를 표현할지 정해주어야 한다. 이러한 경우 사용한다.
  • value
    • TemporalType.DATE
      • 날짜, 데이터베이스 date 타입과 매핑
      • 예) 2013–10–11
    • TemporalType.TIME
      • 시간, 데이터베이스 time 타입과 매핑
      • 예) 11:11:11
    • TemporalType.TIMESTAMP
      • 날짜와 시간, 데이터베이스 timestamp 타입과 매핑
      • 예) 2013–10–11 11:11:11

 

@Lob

  • 데이터베이스 BLOB, CLOB 타입과 매핑하기 위해서 사용한다.
  • 일반적인 데이터타입의 범위를 넘어서는 데이터라면 Lob타입을 사용한다.
  • 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
    • CLOB
      • String, char[], java.sql.CLOB
    • BLOB
      • byte[], java.sql.BLOB

 

@Transient

  • 특정 필드를 DB 컬럼에 매핑하지 않음(매핑 무시)
  • 데이터베이스에 저장되거나 조회되지 않는다.
  • DB와 관계없이 메모리에서만 임시로 어떤 값을 보관하고 싶을 때 사용한다.

 

기본 키 매핑

@Id

  • 값을 직접 할당
  • 여러 코드성 데이터를 조합해서 키를 만드는 경우 사용한다.

 

@GeneratedValue

  • int 보다 Integer를 사용하는 것이 좋다. 그러나 Integer도 10억이 넘어가면 다시 한 바퀴 돈다. 결론은 Long을 사용하는 것이 좋다.
  • 값을 자동으로 생성
  • strategy
    • IDENTITY
      • 이 전략은 기본 키 생성을 데이터베이스에 위임한다.
      • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
        • 예) MySQL의 AUTO_ INCREMENT
      • 주의점
        • 영속성 컨텍스트에서 관리되려면 PK 값이 있어야 한다.
          • 1차 캐시에 저장되는 @Id 는 DB의 PK 값이다.
        • 그러나 이 전략은 DB에 값이 생성될 때 PK 값을 알 수 있다.
        • IDENTITY 전략은 특별하게 트랜잭션 커밋 시점이 아니라, em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회한다.
        • 따라서 SQL을 모아서 처리하는 것은 IDENTITY 전략에서는 불가능하다.

    • SEQUENCE
      • 이 전략은 데이터베이스 시퀀스 오브젝트 사용해서 기본 키를 생성한다.
        • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다.
      • 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
        • 예) 오라클 시퀀스
      • 주의점
        • 영속성 컨텍스트에서 관리하기 위해서 em.persist() 호출 시점에 먼저 시퀀스를 가져온 후 1차 캐시에 저장한다.
          • INSERT SQL 은 실행되지 않는다. 시퀀스를 통해서 PK 값을 얻어올 수 있다.
          • 일반적으로 JPA가 동작하는 것과 같이 트랜잭션 커밋 시점에 SQL이 실행된다.
          • SQL을 모아서 처리하는 것이 가능하다.
        • 그러나 성능상으로 따지고 보면 네트워크 통신이 2번 일어난 것이다.
          • 시퀀스를 통해서 PK 조회
          • INSERT SQL 실행
        • 이러한 관점에서 성능을 향상에 사용할 수 있는 속성이 @SequenceGeneratorallocationSize 속성이다.
          • 저장할 때마다 시퀀스를 통해서 PK 값을 조회해온다면 성능상 문제가 생길 수 있다.
          • 미리 사용할 시퀀스 범위를 할당받아 사용한다면 불필요한 네트워크 통신은 발생하지 않는다.
          • 예) allocationSize 를 50으로 설정
            • 한 번의 시퀀스 호출로 50번까지 사용할 수 있다.
            • 따라서 여러 개 저장한다고 해도 50개 미만이라면 별도의 네트워크 통신(시퀀스 호출) 없이 PK를 설정하여 처리할 수 있다.
            • 동시성 이슈 없이 사용할 수 있다.
              • 미리 시퀀스 값을 확보하여 메모리에 올려두는 방식이기 때문에 시퀀스가 겹치지 않는다.
          @SequenceGenerator(
                  name = "MEMBER_SEQ_GENERATOR",
                  sequenceName = "MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
                  initialValue = 1, allocationSize = 50)
          public class Member {
              @Id
              @GeneratedValue(strategy = GenerationType.SEQUENCE,
                      generator = "MEMBER_SEQ_GENERATOR")
              private Long id;
          		
          		...
          		...
          		...
          }
          public class JpaMain {
          
              public static void main(String[] args) {
                  EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
          
                  EntityManager em = emf.createEntityManager();
                  EntityTransaction tx = em.getTransaction();
                  tx.begin();
          
                  try {
                      Member memberA = new Member();
                      memberA.setUsername("testA");
          
                      Member memberB = new Member();
                      memberB.setUsername("testB");
          
                      Member memberC = new Member();
                      memberC.setUsername("testC");
          
          						//시퀀스 호출은 1회 발생, 시퀀스는 allocationSize 크기만큼 메모리에 저장해서 사용
          						em.persist(memberA); //PK 1, 51
                      em.persist(memberB); //PK 2, MEMORY
                      em.persist(memberC); //PK 3, MEMORY
          
                      tx.commit();
                  } catch (Exception e) {
                      tx.rollback();
                  } finally {
                      em.close();
                  }
                  emf.close();
              }
          }

      • @SequenceGenerator 를 이용하여 테이블별로 사용할 시퀀스를 지정할 수 있다.
      • @SequenceGenerator
        • name
          • 식별자 생성기 이름을 의미한다. 기본값 필수
        • sequenceName
          • 데이터베이스에 등록되어 있는 시퀀스 이름을 설정한다.
          • 기본 값은 hibernate_sequence
        • initialValue
          • DDL 생성 시에만 사용된다.
          • 시퀀스 DDL을 생성할 때 처음 시작하는 수를 설정한다.
          • 기본 값은 1이다.
        • allocationSize
          • 시퀀스 한 번 호출에 증가하는 수를 설정한다.
          • 성능 최적화에 사용된다. 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
          • 기본 값은 50이다.
        • catalog, schema
          • 데이터베이스 catalog, schema 이름을 의미한다.
      • 예)
        @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;
        		
        		...
        		...
        		...
        }

    • TABLE
      • 이 전략은 키 생성용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략이다.
      • 장점은 모든 DB에서 적용 가능하다.
      • 단점은 성능이 문제가 된다.
      • @TableGenerator 를 이용하여 사용할 테이블을 설정할 수 있다.
      • @TableGenerator
        • name
          • 식별자 생성기 이름을 의미한다. 기본값 필수
        • table
          • 기본 키를 생성하는 테이블 이름을 의미한다.
          • 기본 값은 hibernate_sequences
        • pkColumnName
          • 키 생성용 테이블의 시퀀스 이름이 저장되는 컬럼명을 의미한다.
          • 기본 값은 sequence_name
        • valueColumnNa
          • 키 생성용 테이블의 시퀀스 값이 저장되는 컬럼명을 의미한다.
          • 기본 값은 next_val
        • pkColumnValue
          • 키 생성용 테이블에서 키로 사용할 시퀀스 이름을 의미한다.
          • 기본 값은 엔티티 이름으로 설정된다.
        • initialValue
          • 초기 값, 마지막으로 생성된 값이 기준이다.
          • 기본 값은 0이다.
        • allocationSize
          • 시퀀스 한 번 호출에 증가하는 수를 설정한다.
          • SEQUENCE 전략에서 사용되는 특징과 동일하다.
            • 성능 최적화에 사용된다. 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
          • 기본 값은 50이다.
        • catalog, schema
          • 데이터베이스 catalog, schema 이름을 의미한다.
        • (DDL)uniqueConstraints
          • 유니크 제약 조건을 지정할 수 있다.
      • 예)
      @Entity
      @TableGenerator(
      	name = "MEMBER_SEQ_GENERATOR",
      	table = "MY_SEQUENCES", // 테이블 이름
      	pkColumnValue = "MEMBER_SEQ", allocationSize = 1) // PK 컬럼 이름
      public class Member {
      	@Id
      	@GeneratedValue(strategy = GenerationType.TABLE,
      	generator = "MEMBER_SEQ_GENERATOR")
      	private Long id;
      		
      		...
      		...
      		...
      }

    • AUTO
      • 기본 값으로 설정되어 있다.
      • DB 방언에 따라 IDENTITY, SEQUENCE, TABLE 중에 자동 지정한다.
        • 예) ORACLE이면 SEQUENCE 전략으로 동작

[참고자료]

자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한

 

 

반응형

+ Recent posts