본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
JPA? Spring Data JPA? Hibernate?
JPA(Java Persistent API)란?
JPA는 자바 ORM(Object Relational Mapping) 기술에 대한 API 표준 명세를 뜻한다.
ORM 기술이란?
ORM 기술은 말 그대로 객체와 관계형 데이터 베이스를 매핑해 주는 기술이다.
객체는 객체대로, 관계형 데이터베이스는 관계형 데이터베이스대로 설계하고, ORM 프레임워크가 중간에서 매핑을 해준다.
JPA는 라이브러리가 아닌 ORM을 사용하기 위한 인터페이스의 모음이다.
이러한 JPA는 인터페이스의 모음, 단순한 명세이기 때문에 구현이 없다. 자바 애플리케이션에서 관계형 데이터베이스를 어떻게 사용할지 정의하는 하나의 방법일 뿐이다.
따라서 이러한 JPA의 구현체 있어야 JPA를 사용할 수 있다.
Hibernate란?
Hibernate는 JPA를 구현한 구현체이다. 개발된 지 10년이 넘었으며 대중적으로 많이 이용되는 JPA 구현체 중 하나이다
JPA의 핵심들인 EntityManagerFactory, EntityManager, EntityTransaction 등을 상속받아 구현한다.
JPA를 구현하는 다른 구현체들로는 EclipseLink나 DataNucleus 등이 있다.
만약 JPA를 구현하는 구현체들이 마음에 들지 않는다면 개발자가 직접 JPA 구현체를 만들어 사용할 수도 있다.
Hibernate는 내부적으로 JDBC를 이용해 관계형 데이터베이스와 커넥션을 맺고 상호작용한다.
Spring Data JPA란?
Spring Data JPA는 JPA를 사용하기 편하도록 만들어놓은 모듈이다.
Spring Data JPA는 JPA를 한 단계 더 추상화시킨 Repository 인터페이스를 제공한다.
이러한 Spring Data JPA는 Hibernate와 같은 JPA구현체를 사용해서 JPA를 사용하게 된다.
Spring Data JPA를 사용하면 사용자는 더욱 간단하게 데이터 접근이 가능해진다.
JPA 어노테이션
@Entity
- @Entity 어노테이션이 붙은 클래스는 JPA가 관리하는 엔티티이다
- JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션이 필수다
- 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)
- final 클래스, enum, interface, inner 클래스 사용 X
- 저장할 필드에 final 사용 X
- name 속성을 사용하면 JPA에서 사용할 엔티티 이름을 지정할 수 있다.
- 기본값은 클래스 이름을 그대로 사용한다
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
Member(){} // 생략하면 자동으로 생성 but, 다른 생성자가 있으면 자동 생성 안됨
}
@Table
- @Table 어노테이션은 엔티티와 매핑할 테이블을 지정한다.
- name 속성으로 매핑할 테이블 이름 지정이 가능하다
- 기본값은 엔티티 이름이다
@Entity
@Table(name = MEMBERS)
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
Member(){} // 생략하면 자동으로 생성 but, 다른 생성자가 있으면 자동 생성 안됨
}
필드와 컬럼 매핑
@Entity
public class Member {
@Id
private Long id;
@Column(name = "name")
private String username;
private Integer age;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
//Getter, Setter…
}
@Column
속성 | 설명 | 기본값 |
name | 필드와 매핑할 테이블의 컬럼 이름 | 객체의 필드 이름 |
insertable, updatable | 등록, 변경 가능 여부 | TRUE |
nullable(DDL) | null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다. | |
unique(DDL) | @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제 약조건을 걸 때 사용한다. | |
columnDefinition (DDL) | 데이터베이스 컬럼 정보를 직접 줄 수 있다. ex) varchar(100) default ‘EMPTY' | 필드의 자바 타입과 방언 정보를 사용해 |
length(DDL) | 문자 길이 제약조건, String 타입에만 사용한다. | 255 |
precision, scale(DDL) | BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다). precision은 소수점을 포함한 전체 자 릿수를, scale은 소수의 자릿수 다. 참고로 double, float 타입에는 적용되지 않는다. 아주 큰 숫자나 정 밀한 소수를 다루어야 할 때만 사용한다 | precision=19, scale=2 |
@Enumerated
- 자바 enum 타입을 매핑할 때 사용
속성 | 설명 | 기본값 |
value | - EnumType.ORDINAL: enum 순서를 데이터베이스에 저장 - EnumType.STRING: enum 이름을 데이터베이스에 저장 |
기본값은 ORDINAL이지만, ORDINAL을 사용하지 않는 게 좋다.
예를 들어
public enum RollType {
ACTOR, PROGRAMMER, CEO // 0,1,2
}
위와 같은 enum 타입 클래스를 정의했다고 하자.
ACTOR, PROGRAMMER, CEO는 순서대로 0,1,2를 나타낸다.
만약 value 속성을 @Enumerated(value = EnumType.ORDINAL)로 하면 순서인 0,1,2를 저장한다
이때 RollType이 아래와 같이 변한다고 하자.
public enum RollType {
DANCER, ACTOR, PROGRAMMER, CEO // 0,1,2,3
}
DANCER라는 값이 앞에 추가되면서 기존의 순서가 깨져버린다. 이렇게 되면 데이터베이스에 저장된 ACTOR=0, PROGRAMMER=1, CEO=2 등의 순서와 정합성이 맞지 않게 된다.
반면 EnumType.STRING을 사용하면 enum 이름 그대로 저장하기 때문에 enum 값이 변하더라도 문제가 없다.
@Temporal
- 날짜 타입(java.util.Date, java.util.Calender)을 매핑할 때 사용
- 최신 하이버네이트가 지원하는 LocalDate, LocalDateTime을 사용할 때는 생략 가능하다.
속성 | 설명 | 기본값 |
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 타입과 매핑
- 지정할 수 있는 속성이 없다
- 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
@Transient
- 해당 어노테이션이 붙은 필드는 매핑하지 않는다
- 따라서 데이터베이스에 저장되지도, 조회되지도 않는다
- 주로 메모리상에서만 임시로 값을 보관하고 싶을 때 사용한다
기본키 매핑 어노테이션
- 직접 기본키를 할당하려면 @Id 어노테이션만 사용
- 자동 생성하려면 @GeneratedValue 어노테이션 사용
@GeneratedValue
IDENTITY 전략
- 기본 키 생성을 데이터베이스에 위임
- 주로 MySQL, PostgreSQL, SQL Server, DB2 등에서 사용 (예시 : MySQL의 AUTO_INCREMENT)
- JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL을 실행한다
- AUTO_INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 ID 값을 알 수 있다
- IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행 후 DB에서 식별자를 조회한다
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
SEQUENCE 전략
- 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(예시 : 오라클 시퀀스)
- 오라클, PostgreSQL, DB2, H2 데이터베이스 등에서 사용
@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;
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는 수를 지정한다. | 1 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨)데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다 | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 |
TABLE 전략
- 키 생성 전용 테이블을 하나 만들어 데이터베이스 시퀀스를 흉내 내는 전략
- 모든 데이터베이스에 적용 가능하지만 성능이 좋지 않다
'패스트캠퍼스 강의' 카테고리의 다른 글
[21일차] 50일 포트폴리오 챌린지 (0) | 2023.08.28 |
---|---|
[20일차] 50일 포트폴리오 챌린지 (1) | 2023.08.27 |
[18일차] 50일 포트폴리오 챌린지 (0) | 2023.08.25 |
[17일차] 50일 포트폴리오 챌린지 (0) | 2023.08.24 |
[16일차] 50일 포트폴리오 챌린지 (0) | 2023.08.23 |