ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 단일 엔티티 매핑
    Backend/Spring 2022. 8. 24. 17:40
    728x90

    단일 엔티티 매핑

    JPA는 엔티티 객체를 생성할 때, 기본 생성자 (Default Constructor)를 사용한다.

     

    @Entity : 영속성 컨텍스트에서 관리하는 객체임을 알림

    속성 설명
    name JPA에서 사용할 엔티티 이름을 지정한다.

    @Table : 엔티티 객체와 RDB 테이블간의 매핑

    속성 설명
    name 매핑할 테이블 이름
    @Table(name = "member")
    public class Member {
        @Id
        private Long id;
        private String name;
        private String nickName;
        private int age;
        private String address;
        private String description;
    
    	// getter, setter
    }

     

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

    spring:
      h2:
        console:
          enabled: true
      jpa:
        generate-ddl: true
        database: H2
        show-sql: true
        open-in-view: false
        properties:
          hibernate:
            dialect: org.hibernate.dialect.H2Dialect
            query.in_clause_parameter_padding: true
            hbm2ddl:
              auto: create-drop

     

    AUTO DDL 옵션

    옵션 설명
    create
    : 개발, 테스트 환경
    기존 테이블을 삭제하고 새로 테이블을 생성한다. (DROP + CREATE)
    create-drop
    : 개발, 테스트 환경
    어플리케이션 종료시 생성한 DDL을 제거한다. (DROP + CREATE + DROP)
    보통 테스트코드 작성 시 하나의 테스트 종료 후 다른 테스트에 영향을 주지 않기 위해서 사용한다.
    update
    : 개발, 테스트 환경
    테이블, 엔티티 매핑정보를 비교하여 변경사항을 수정한다.
    validate
    : 운영환경
    테이블, 엔티티 매핑정보를 비교해서 차이가 있으면 경도를 남겨 어플리케이션을 실행하지 않는다.
    차이가 있으면 오류를 발생시킨다.
    none 자동 생성 기능을 사용하지 않는다.

     

    DDL 옵션

    @Entity
    @Table(name = "member")
    @Getter
    @Setter
    public class Member {
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private Long id;
    
        @Column(name = "name", nullable = false, length = 30)
        private String name;
    
        @Column(nullable = false, length = 30, unique = true)
        private String nickName; // nick_name
    
        private int age; // age
    
        @Column(name = "addres", nullable = false)
        private String address;
        
        @Column(name = "description", nullable = true)
        private String description;
    }

    @Column

    속성 설명 기본값
    name 필드와 매핑할 테이블 컬럼 이름( default는 feild명, camel case는 under score로 변경해줌) 객체의 필드 이름
    insertable 엔티티 저장시 필드도 같이 저장한다. false이면 읽기 전용으로 사용한다.  true
    updateable 엔티티 수정시 필드도 같이 수정한다. false이면 읽기 전용으로 사용한다. true
    nullable(DDL) null값 허용 여부를 설정한다. false이면 NOT NULL 제약조건이 추가된다. true
    length(DDL) 문자 길이의 제약조건으로 사용된다. (String type에만 사용) 255
    unique(DDL) 해당 컬럼의 RDB의 제약조건인 unique 제약조건을 추가한다.  
    drop table if exists member CASCADE 
    drop sequence if exists hibernate_sequence
    create sequence hibernate_sequence start with 1 increment by 1
    create table member (id bigint not null, address varchar(255) not null, age integer not null, description varchar(255), name varchar(30) not null, nickName varchar(30) not null, primary key (id))
    alter table member add constraint UK_1m3ighjll05v7njjxeopp823j unique (nickName)

     

    기본키 매핑 전략

    @Id

    RDB 테이블의 primary key가 되며 영속성 컨텍스트에서 1차 캐시의 key값으로 사용된다.

    • 직접 할당
      • 영속화 전에 애플리케이션에서 직접 값을 할당한다.
    @Id
    @Column(name = "id")
    private Long id;

     

    • SEQUENCE
      • 데이터베이스 시퀸스에서 식별자 값을 획득한 후 영속화
      • ORACLE, H2
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

     

    • TABLE
      • 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속화

     

    • IDENTITY
      • 데이터베이스 엔티티를 저장해서 식별자 값을 획득한 후 영속화
      • 엔티티가 영속화 되려면 식별자 값이 반드시 필요하기 때문에, em.persist() 시점에 INSERT쿼리가 수행된다.
      • MySQL(AUTO_INCREMENT)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

     

    • AUTO
      • 데이터베이스 방언(dialect)에 따라서 자동으로 전략을 선택
      • 어떤 RDB를 사용해도 이것에 맞게 쿼리를 수행할 수 있도록 엔진에 맞는 쿼리를 만들어 준다.
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Id
    @GeneratedValue
    private Long id;

     

    기타 컬럼 매핑

    @Entity
    @Table(name = "orders")
    public class Order {
    
        @Id
        @Column(name = "id")
        private String uuid;
    
        @Column(name = "order_datetime", columnDefinition = "TIMESTAMP")
        private LocalDateTime orderDatetime;
    
        @Enumerated(EnumType.STRING)
        private OrderStatus orderStatus;
    
        @Lob // long text 타입의 필드 생성
        private String memo;
    }

     

    데이터 중심 설계의 문제점

    create sequence hibernate_sequence start with 1 increment by 1
    create table item (id bigint not null, price integer not null, stockQuantity integer not null, primary key (id))
    create table member (id bigint not null, address varchar(255) not null, age integer not null, description varchar(255), name varchar(30) not null, nickName varchar(30) not null, primary key (id))
    create table order_item (id bigint not null, item_id bigint, order_id varchar(255), price integer not null, quantity integer not null, primary key (id))
    create table orders (id varchar(255) not null, member_id bigint, memo clob, order_datetime TIMESTAMP, orderStatus varchar(255), primary key (id))
    alter table member add constraint UK_1m3ighjll05v7njjxeopp823j unique (nickName)
    • JPA DDL 옵션을 사용해서, 설계한 ERD로 DDL 쿼리가 수행된다.

     

    • 설계한 엔티티로 DB스키마를 설계하면 설계한 ERD 형태로 테이블이 생성되기는 하지만, 실제 엔티티 객체 사이에는 서로 참조하지 않고 있다.
    • 만약 특정 Order에 대해 연관된 Member를 알고 싶다면, 특정 Order를 조회하여 회원 id를 가져온 후 회원 id로 다시 회원을 조회하는 과정이 필요하다.
    • 데이터 중심 설계로 인해 잘못된 JPA 엔티티 객체 사용
    • 이는 객체 중심 설계와는 맞지 않는 방식!
    728x90

    댓글

Designed by Tistory.