Persistence
클래스가 설정 파일을 읽고EntityManagerFactory
를 생성하고EntityManagerFactory
가 필요할 때 마다EntityManager
를 생성한다.
엔티티 매핑
import javax.persistence.*;
import java.util.Date;
@Entity
//@Table
public class Member {
@Id
private Long id;
@Column(name="name", columnDefinition = "varchar(100) default 'EMPTY'")
private String username;
private Integer age;
@Enumerated(EnumType.STRING)
private RoleType rolType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
@Transient
private int temp;
public Member() {
}
}
- JPA를 사용해서 테이블과 매핑할 클래스에
@Entity
를 붙인다. (필수)- 파라미터가 없는 public 또는 protected 기본 생성자를 필수로 선언
- final 클래스, enum, interface, inner 클래스는 사용할 수 없다.
- 저장할 필드에 final은 사용할 수 없다.
- name 속성 : JPA에서 사용할 엔티티 이름을 지정할 수 있다. 기본 값으로 클래스 이름을 그대로 사용하기 때문에 같은 클래스 이름이 없으면 가급적 기본 값을 사용한다.
- 엔티티와 매핑할 테이블을 지정하기 위해
@Table
로 표시한다.- name 속성 : 테이블과 엔티티의 이름이 다를 경우 매핑할 테이블 이름을 지정한다. (기본 값 : 엔티티 이름)
- catalog 속성 : 데이터베이스 catalog 매핑
- schema 속성 : 데이터베이스 schema 매핑
- uniqueConstraints(DDL) 속성 : DDL 생성 시에 유니크 제약 조건 생성
@Id
는 PK를 나타낸다.@Column
: 컬럼 매핑- name 속성 : 컬럼명과 필드명이 다를 경우 컬럼명을 지정한다. (기본 값 : 필드명)
- insertable 속성 : 등록 가능 여부 (기본 값 true)
- updatable 속성 : 수정 가능 여부. 만약 컬럼 값이 절대로 변경되지 않아야 한다면 false로 설정한다.
- nullable(DDL) 속성 : null 값의 허용 여부 설정. not null 제약조건으로 DDL을 생성하려면 false로 설정한다.
- unique(DDL) 속성 : @Table의 uniqueConstraints와 와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다. 단, 제약조건 아이디가 랜덤 값으로 생성되기 때문에 잘 쓰이지 않는다. @Table를 통해 설정하는 편이다.
- columnDefinition(DDL) 속성 : 필드의 자바 타입과 방언 정보를 사용해 데이터베이스 컬럼 정보를 직접 설정할 수 있다.
- length(DDL) 속성 : 문자 길이 제약조건. String 타입에만 사용한다. (기본 값 : 255)
- precision, scale(DDL) 속성 : BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다). precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다. (double, float 타입에는 적용되지 않는다.) 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
@Enumerated
: enum 타입 매핑- EnumType.ORDINAL : enum 순서를 데이터베이스에 저장한다. 기본 값
- EnumType.STRING : enum 이름을 데이터베이스에 저장한다.
- 절대로 기본 값인 EnumType.ORDINAL을 설정해서는 안 된다. DB에 enum의 순서 값이 저장되기 때문에 만약 추후에 enum이 새로 추가 앞에 된다면 문제가 되기 때문이다.
@Temporal
: 날짜 타입(java.util.Date, java.util.Calendar) 매핑- TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑
- TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑
- TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑
- 최신 하이버네이트에서는 LocalDate(date 타입)나 LocalDateTime(timestamp 타입) 타입을 지원하기 때문에 @Temporal을 생략할 수 있다.
@Lob
: BLOB, CLOB 매핑- 속성이 없다.
- 매핑하는 필드 타입이 문자면 CLOB로 나머지는 BLOB로 매핑된다.
- CLOB: String, char[], java.sql.CLOB
- BLOB: byte[], java.sql. BLOB
@Transient
: 필드를 컬럼에 매핑하지 않고 주로 메모리에서 임시로 사용하기 위한 설정 (매핑 무시)- DDL 생성 기능
- 회원 이름은 필수, 10자 제한과 같이 컬럼의 제약 조건 추가
- @Column(nullable = false, length = 10)
- 유니크 제약조건 추가
- @Table(uniqueConstraints = {@UniqueConstraint( name = “NAME_AGE_UNIQUE”, columnNames = {“NAME”, “AGE”} )})
- DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
- 회원 이름은 필수, 10자 제한과 같이 컬럼의 제약 조건 추가
실행하기
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//트랜잭션 시작 : JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
//등록
Member member = new Member();
member.setId(2L);
member.setName("HelloB");
em.persist(member);
//조회
Member member = em.find(Member.class, 1L);
System.out.println("아이디 : " + member.getId());
System.out.println("이름 : " + member.getName());
//삭제
Member member = em.find(Member.class, 2L);
em.remove(member);
//수정
Member member = em.find(Member.class, 1L);
member.setName("HelloJPA");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close(); //애플리케이션 종료 시 닫아주어야 한다.
}
}
EntityManagerFactory
는 애플리케이션 로딩 시점에 DB 당 하나만 생성되어 애플리케이션 전체에서 공유된다.- createEntityManagerFactory에 들어가는 값은 JPA 설정파일에 설정한 persistence-unit 이름을 나타내며 해당 설정 정보를 불러온다.
EntityManager
는 요청이 올 때마다 계속 생성, 삭제되면서 동작한다. 내부적으로 데이터베이스 커넥션을 생성하여 데이터베이스에 접근한다.- 쓰레드 간에 공유해선 안 되고 사용하고 버려야 한다.
- JPA는
EntityManager
를 통해 작업한다.
- 수정할 때
member.setName("HelloJPA");
과 같이 마치 자바 컬렉션을 다루는 것처럼 setter만 호출하면 update된다.- JPA를 통해 데이터를 가져오면 이를 JPA가 관리하게 되고 변경된 값이 있는지 트랜잭션 커밋 전에 체크한다.
- 바뀐 게 있으면 update 쿼리를 만들어 날린 후에 커밋한다.
- 스프링과 JPA를 함께 사용하면 EntityManagerFactory나 EntityManager 등의 작업을 스프링이 맡게 된다.