• 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의 실행 로직에는 영향을 주지 않는다.

실행하기

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 등의 작업을 스프링이 맡게 된다.