백엔드/JPA

[JPA] [4] 엔티티 매핑(상편)

RE-Heat 2023. 8. 5. 13:50

https://www.inflearn.com/course/ORM-JPA-Basic

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

초급자를 위해 준비한 [웹 개발, 백엔드] 강의입니다. JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자

www.inflearn.com

인프런 김영한 님의 강의를 듣고 작성한 글입니다.

 

 

엔티티 매핑 소개

  • 객체와 테이블 매핑: @Entity, @Table
  • 필드와 컬럼 매핑: @Column
  • 기본 키 매핑: @Id
  • 연관관계 매핑: @ManyToOne,@JoinColumn

 

[1] 객체와 테이블 매핑

■ @Entity

  • @Entity가 붙은 클래스는 JPA가 관리, 엔티티라 한다.
  • JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수
  • 주의
    • 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)
    • final 클래스, enum, interface, inner 클래스 사용 X
    • 저장할 필드에 final 사용 X

reflection 등에서 쓰이므로 기본 생성자는 필수다.

 

■ @Entity name 속성

  • JPA에서 사용할 엔티티 이름을 지정
  • 기본값 : 클래스 이름을 그대로 사용(예: Member)
  • 같은 클래스 이름이 없으면 가급적 기본값을 사용한다.

다른 패키지에 같은 클래스 이름이 있을 때 쓰이며 웬만하면 기본값을 써야 한다.

 

■ @Table

@Table은 엔티티와 매핑할 테이블을 지정할 때 쓰인다.

 

MBR이라는 테이블에 select문을 날리는 걸 확인할 수 있다.

 

 

[2] 데이터베이스 스키마 자동 생성

JPA는 매핑 정보를 확인하면 어떤 쿼리·테이블이 필요한지 알 수 있다. 따라서 JPA에는 애플리케이션 로딩 시점에 DB 테이블을 생성하는 자동 기능도 제공한다.

 

  • DDL을 애플리케이션 실행 시점에 자동 생성
  • 테이블 중심 → 객체 중심
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL 생성
  • 이렇게 생성된 DDL은 개발 장비에서만 사용
  • 생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용

 

■ 속성

 

① create

옵션을 create로 해주면 기존에 같은 이름의 테이블이 있으면 drop한 뒤 새로 생성해 준다. 필드도 알아서 추가해 준다.

 

② create-drop : 종료시점에 테이블을 DROP하는 게 차이점으로 테스트 케이스에 보통 활용된다.

 

③ update : 변경된 내역만 반영된다.

age필드를 추가하니 alter로 필드를 추가해 주는 걸 확인할 수 있다.

단, 여기서 age필드를 다시 지우고 실행해도 update옵션은 삭제 쿼리는 날리지 않는다.

 

④ validate : 엔티티 테이블이 정상 매핑됐는지 확인해 준다.

멤버 테이블에 없는 gogo필드를 넣으면 그 칼럼을 찾을 수 없다는 로그가 뜬다.

 

참고] 스키마 자동생성도 데이터 베이스 방언 별로 다르게 생성된다.

ex) 오라클

오라클이라 VARCHAR2가 들어갔다.

 

■ 주의점

  • 운영 장비에는 절대 create, create-drop, update 사용하면 안 된다.
  • 개발 초기 단계는 create 또는 update
  • 테스트 서버는 update 또는 validate
  • 스테이징과 운영 서버는 validate 또는 none

create를 잘못 사용하면 drop문이 날아가 테이블 내역이 통째로 날아갈 수 있다.

update문도 날아가면 데이터베이스 락이 걸려 서비스가 몇 분 다운될 수 있어서 운영 장비에선 쓰면 안 된다.

 

■ DDL 생성 기능

  • 제약조건 추가 : 예) 회원 이름은 필수, 10자 초과 X
    @Column(nullable = false, length = 10)
  • 유니크 제약조건 추가
    @Table(uniqueConstraints = {@UniqueConstraint(name ="NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"})})

DDL 생성기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

 

제약조건을 추가하니 ① alter문으로 name에 관한 unique가 설정된 걸 알 수 있다. ② length도 10으로 된 걸 확인 가능.

 

[3] 필드와 컬럼 매핑

 

■ 요구사항

① 회원은 일반 회원과 관리자로 구분해야 한다.
② 회원 가입일과 수정일이 있어야 한다.
③ 회원을 설명할 수 있는 필드가 있어야 한다. 이 필드는 길이 제한이 없다.

 

 

RoleType(일반회원, 관리자) - enum 클래스

public enum RoleType {
    USER, ADMIN
}

 

Member

@Entity//이걸 넣어야 JPA 사용하는지 인식할 수 있음
public class Member {
    @Id
    private Long id;

    @Column(name = "name", nullable = false)//db 컬럼명은 name
    private String username;

    private Integer age;

    @Enumerated(EnumType.STRING)//DB엔 enum이 없어서 이렇게 써야 함.
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    private LocalDate testLocalDate;
    private LocalDateTime testLocalDateTime;

    @Temporal(TemporalType.TIMESTAMP) //DATE(날짜), TIME(시간), TIMESTAMP(날짜/시간)
    private Date lastModifiedDate;

    @Lob //DB에 varchar를 넘어서는 큰 컨텐츠를 넣고 싶을 때
    private String description;

    @Transient
    private int temp;
    
 }

 

■ @Column 속성

1. name을 쓸 땐 db 칼럼명과 일치하게 하기 위해 쓴다. 보통 default값 씀

2. insertable = false: insert 시점에 막는 기능 updateable = false : update 시점에 막는 기능

3. nullable : not null 제약조건이 붙어 자주 사용된다.

4. unique : unique를 쓰면 자동으로 붙는 unique의 이름을 알아먹기 어려워 보통 @Table(uniqueConstraints = )를 쓴다.

5. columnDefinition : 직접 컬럼 정보 수정 가능

6. length : 문자 길이 제약

7. precision : 숫자가 엄청 큰 BigDecimal 등에서 사용된다.

 

■ @Enumerated

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

 

① EnumType.ORDINAL: enum 순서를 데이터베이스에 저장 (디폴트값)

② EnumType.STRING: enum 이름을 데이터베이스에 저장

 

※ 주의

순서를 DB에 저장하는 EnumType.ORDINAL은 사용하지 않는다. 만일 RoleType에 수정이 있어 GUEST, USER, ADMIN으로 순서가 변경될 경우 기존 0번이던 USER와 새로운 0번인 GUEST가 겹쳐 구분하기 어렵기 때문이다.

1번째 ROLETYPE은 USER, 3번째는 GUEST나 ORDINAL을 사용하면 둘 다 0번으로 들어가는 불상사가 발생한다.

 

■ @Temporal

날짜 타입 매핑에 사용 (java.util.Date, java.util.Calendar)

① TemporalType.DATE: 날짜, 데이터베이스 date 타입과 매핑 (예: 2013–10–11) 
② TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑 (예: 11:11:11) 
③ TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이스 timestamp 타입과 매핑

    (예: 2013–10–11 11:11:11)

 

LocalDate, LocalDateTime을 사용할 땐 생략이 가능하다.

 

■ @Lob

DB에 varchar를 넘어선 큰 값을 넣고 싶을 때 해당 annotation을 사용한다.

  • @Lob에는 지정할 수 있는 속성이 없다.
  • 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
    • CLOB: String, char[], java.sql.CLOB
    • BLOB: byte[], java.sql. BLOB

 

■ @Transient

특정 필드를 매핑하지 않는다.

주로 메모리 상에서 임시로 어떤 값을 보관하고 싶을 때 사용된다.