[JPA] Entity

Gajun Choi·2022년 9월 19일
0

JPA

목록 보기
4/4

요약

  1. Entity LifeCycle
  2. Entity Mapping

1. Entity LifeCycle (생명주기)

1.1 종류

  • 비영속 : Persistence Context와 전혀 관계 없는 상태
  • 영속 : Persistence Context에 저장된 상태
  • 준영속 : Persistence Context에 저장되었다가 분리된 상태
  • 삭제 : 실제 DB 삭제를 요청한 상태

1.2 영속과 준영속

  • 영속상태
    • entityManager.persist(); 로 Persistence Context에 저장된 상태
    • entityManager.find(); 로 조회할 때 Persistence Context 1차 cash에 없어서 DB에서 조회한 후 해당 Entity를 1차 캐시에 올린 상태(Entity Manager 가 관리하는 상태)
  • 준영속 상태
    • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)된 상태
    • 준영속 상태에서는 Persistence Context가 제공하는 기능을 못 씀(Dirty Checking, Query)
  • EX)
Member member = entityManager.find(Member.class, 150L); // 영속 상태
member.setName("AAAAA");
transaction.commit();
  • entityManager.find() : 1차 캐시에 없으므로 DB에서 조회한 Entity를 1차 캐시에 넣음(영속)
  • Dirty Checking (변경감지)
    • 이름 변경에 대한 Entity 데이터 변화를 감지 (Snapshot)
    • 1차 캐시의 Entity와 Snapshot의 차이를 감지하고 Update Query를 날림

1.3 준영속 상태로 만드는 법(영속 -> 준영속)

  1. entityManager.detach(entity) : 특정 Entity만 준영속 상태로 전환
  2. entityManager.clear() : Persistence Context 를 완전 초기화
  3. entityManager.close() : Persistence Context 를 종료

Detach

// 영속 상태 (Persistence Context 에 의해 Entity 가 관리되는 상태)
Member findMember = entityManager.find(Member.class, 150L);
findMember.setName("AAAAA");

entityManager.detach(findMember); // 영속성 컨텍스트에서 떼넨다. (더 이상 JPA 의 관리 대상이 아님.)

tx.commit(); // DB에 insert query 가 날라가는 시점 (아무 일도 발생하지 않음.)
  • entityManager.detach(); : 해당 Entity를 Persistence Context에서 분리(JPA가 관리하지 않는 객체 상태)
  • Transaction Commit 에서 아무 일도 발생하지 않음
  • Entity가 변경되었는데 실제로 UPDATE Query 가 나가지 않음
  • 직접 쓸 일이 거의 없음

Clear

// 영속 상태 (Persistence Context 에 의해 Entity 가 관리되는 상태)
Member findMember = entityManager.find(Member.class, 150L);
findMember.setName("AAAAA");

entityManager.clear(); // 영속성 컨텍스트를 완전히 초기화

Member findMember2 = entityManager.find(Member.class, 150L); // 간은 Entity 를 다시 조회

tx.commit(); // DB에 insert query 가 날라가는 시점 (아무일도 발생하지 않음.)
  • entityManager.clear(); " EntityManager 안에 있는 Persistence Context를 모두 지움(초기화)
    = clear 후 Entity를 조회할 때 SELECT Query 가 두 번 발생
  • clear는 1차 캐시에 상관없이 쿼리를 확인하고 싶을 때 즉, testcase 작성 시에 도움이 된다.

Close

  • Persistence Context 종료
  • JPA의 관리 대상이 아니게 됨

2. Entity Mapping

JPA 핵심

  • Persistence Context, JPA 내부 동작 매커니즘
  • 객체와 RDB 매핑

2.1 Mapping 종류

  • 객체와 테이블 매핑 ( @Entity / @Table )
  • 필드와 컬럼 매핑 ( @Column )
  • 기본키 매핑 ( @ID )
  • 연관관계 매핑 ( @ManyToOne / @JoinColumn )

2.2 객체와 테이블 매핑

@Entity

  • @Entity 가 붙은 클래스는 JPA가 관리하는 클래스로, 해당 클래스를 Entity라 함 (필수)
  • 기본 생성자가 필요하다.
  • final 클래스, enum, interface, inner 클래스는 Entity로 사용 불가
  • DB에 저장하고 싶은 필드에는 final 사용 불가
  • Entity 속성
    • @Entity(name = "Member") - JPA레서 사용할 Entity 이름 지정
    • 기본값 : 클래스 이름 그대로 사용

@Table

  • @Table은 Entity와 Mapping할 Table 지정
  • Table 속성 [ @Table(name = "MBR") ]
    • name : 매핑할 테이블 이름 (기본값으로 Entity 이름 사용)
    • catalog : DB catalog 매핑
    • schema : DB schema 매핑
    • uniqueConstraints(DDL) : DDL 생성시 유니크 제약 조건 생성

2.3 DB와 Schema 자동 생성

2.3.1 체크사항

  • application 로딩 시점에 DDL을 자동으로 생성

  • 테이블 중심 -> 객체 중심

  • 이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.
    Ex) oracle: varchar2, MySQL: varchar 등

  • 생성된 DDL은 로컬에서만 사용 ... ?

    	<property name="hibernate.hbm2ddl.auto" value="create"/>
  • 속성 값(value)

옵션설명
create기존 테이블 삭제 후 다시 생성(DROP + CREATE)
create-dropcreate와 같으나 종료 시점에 테이블 DROP(Test에서 자주 사용)
update변경 분만 반영(운영 DB에서는 사용하면 안됨) alter table ~
validate엔티티와 테이블이 정상 매핑되었는지만 확인
none속성 사용 X

[주의]

  • 운영 장비에는 절대 create-drop, update 를 사용하면 안된다.

  • 개발 초기 단계(로컬 개발 서버) - create / update

  • 테스트 서버 - update / validate / none
    = 데이터가 많은 상태에소 alter 했을 때 시스템 중단될 수도 있다함 -> DBA에게 검수 받고 적용 추천!

  • 스테이징과 운영서버 - validate / none

    2.3.2 DDL 생성 기능

  • 제약 조건 추가 기능

    • @Column(nullable = false, length = 10)
      = 회원 이름 필수 / 10글자 초과 x
    • @Column(unique = true)
      = 해당 필드는 unique
    • @Table(uniqueConstraints = {@UniqueConstraint(name = "NAME_AGE_UNIQUE",
      columnNames = {"NAME", "AGE"})})
      = unique 제약 조건 추가
  • DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA 실행 로직에는 영향을 주지 않는다.

    • 즉, DB에만 영향을 주는 것이지 애플리케이션에 영향을 주는 것이 아니다.
    • JPA의 실행 매커니즘에 영향을 주는 것이 아니라 alter table과 같은 스크립트가 실행되는 것을 말한다.
      Cf) insert, update는 Runtime에 영향을 준다.

2.4 필드와 컬럼 매핑

2.4.1 요구사항 추가

  1. 회원은 일반 회원과 관리자로 구분
  2. 회원 가입일과 수정일이 있어야 함
  3. 회원을 설명할 수 있는 필드가 있어야 함
public enum RoleType {
  USER, ADMIN
}
@Entity

// name과 age 컬럼에 unique 제약조건 추가
@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint(
			name = "NAME_AGE_UNIQUE",
            columnNames = {"NAME", "AGE"} )})
public class Member {
  @Id									// PK 매핑
  private Long id;

  // not null, varchar(10)    
  @Column(name = "NAME", nullable = false, length = 10)    private String username;

  private Integer age;

  // 자바의 enum 사용
  @Enumerated(EnumType.String)
  private RoleType roleType;

  @Temporal(TemporalType.TIMESTAMP)
  private Date createDate;

  @Temporal(TemporalType.TIMESTAMP)
  private Date lastModifiedDate;

  // CLOB, BLOC 타입 매핑
  @Lob
  private String description;

  @Transient
  private int temp;

  public Member() {

  }
}
create table Member (
  id bigint not null,
  age integer,
  createdDate timestamp,
  description clob,
  lastModifiedDate timestamp,
  roleType varchar(255),
  name varchar(255),
  primary key (id)
)

@Id

  • PK 매핑

@Column

  • 컬럼 매핑
  • @Column 속성
    • name [ @Column(name = "name") ] : 객체명과 DB컬럼을 다르게 하고싶은 경우 name에 정의
    • insertable
    • updatable
      • 컬럼 수정했을 때 DB에 추가할 것인지 여부
      • update 문이 나갈 때 해당 컬럼을 반영할 것인지 여부
      • @Column(updatable = false) : 변경이 되어도 DB에 반영하지 않는다.
    • nullable
      • @Column(nullable = false) : NOT NULL 제약 조건
    • unique
      • 잘사용하지 않음
    • columnDefinition
      • @Column(columnDefinition = "varchar(100) default 'EMPTY'") : 컬럼 정보 직접 입력
    • length
      • String 타입에만 사용하는 문자 길이 제약 조건
    • precision
      • 숫자가 엄청 큰 BigDecimal 의 경우 (EX - private BigDecimal age;)

@Enumerated

  • Enum Type 매핑

    • Enum 객체 사용 시 해당 annotation을 사용
    • DB에는 Enum Type 이 없음
  • EnumType.String

    • enum 이름을 DB에 저장
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Enumerated {
      EnumType value() default EnumType.ORDINAL;
    }
    
    public enum EnumType {
      ORDINAL, STRING;
      private EnumType() { }
    }
    

@Temporal

  • 날짜 Type (java.util.Date, java.util.Calendar) 매핑
  • 날짜 타입 사용 시 해당 annotation을 사용
  • java의 Date에는 날짜와 시간이 모두 존재한다. 그러나 DB의 Date에는 아래의 세 가지로 구분해서 사용한다
  • TemporalType enum class에는 세 가지가 존재한다.
    • DATE: 날짜, DB의 date 타입과 매핑
      Ex. 2019-08-13
    • TIME: 시간, DB의 time 타입과 매핑
      Ex. 14:20:38
    • TIMESTAMP: 날짜와 시간, DB의 timestamp 타입과 매핑
      Ex. 2019-08-13 14:20:38

@Lob

  • DB에서 varchar를 넘어서는 큰 내용을 넣고 싶은 경우에 해당 annotation을 사용
  • @Lob에는 지정할 수 있는 속성이 없다.
  • 매핑하는 필드의 타입에 따라 DB의 BLOB, CLOB과 매핑된다.
    • 필드의 타입이 문자열: CLOB
      • String, char[], java.sql.CLOB
    • 그 외 나머지: BLOB
      • byte[], java.sql.BLOB

@Transient

  • 특정 필드를 컬럼에 매핑하지 않음.
  • DB에 관계없이 메모리에서만 사용하고자 하는 객체에 해당 annotation을 사용
    • 즉, 주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용한다.
  • 해당 annotation이 붙은 필드는 DB에 저장, 조회가 되지 않는다.

참조

https://gmlwjd9405.github.io/2019/08/11/entity-mapping.html

profile
개발하는헬창

0개의 댓글