🍃프로그래머스 백엔드 데브코스 4기 교육과정을 듣고 정리한 글입니다.🍃
영속성 컨텍스트
EntityManagerFactory
그림 출처
- Entity를 관리하는 EntityManager를 생산하는 객체
- Thread Safe
EntityManager
- Entity를 저장, 수정, 삭제, 조회하는 Entity와 관련된 모든 일을 처리
- Thread Safe 하지 않기 때문에 여러 Thread에서 동시에 접근하면 동시성 이슈가 발생
영속성 컨텍스트
그림 출처
- Entity를 영구 저장하는 환경
- EntityManager는 Entity를 영속성 컨텍스트에서 보관하고 관리
- 영속성 컨텍스트와 식별자 값
- 영속성 컨텍스트 안에서 관리되는 엔티티는 식별자 값을 반드시 가져야 한다.
- key-value로 엔티티를 관리한다.
- key에 pk(id)값이 아니라, 다른 식별자(name)로 관리할 수 있다.
- 영속성 컨텍스트와 데이터베이스 저장
- JPA는 트랜잭션을 커밋하는 순간 flush를 통해 영속성 컨텍스트에 새로 저장된 엔티티를 DB에 반영한다.
- flush는 영속성 컨텍스트의 변경 내용을 DB에 동기화하는 작업인데, 이때 등록, 수정, 삭제한 엔티티를 DB에 반영한다.
- 영속성 컨텍스트가 엔티티를 관리함으로 얻는 이점
- 1차 캐치
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
엔티티 생명주기
- 비영속(new/transient): 영속성 컨텍스트와 전혀 관계가 없는 상태
Customer customer = new Customer();
customer.setFirstName("myeonghan");
customer.setLastName("yu");
- 영속(managed): 영속성 컨텍스트에 저장된 상태
Customer customer = new Customer();
customer.setFirstName("myeonghan");
customer.setLastName("yu");
em.persist(customer);
- 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(customer);
em.clear()
em.close()
em.remove(customer)
영속성 컨텍스트 실습
저장
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Customer("명한", "유");
em.persist(customer);
transaction.commit();
- customer가 영속화 되면서 쓰기 지연 저장소에 insert 쿼리가 저장된다.
- customer가 영속화 되면서 1차 캐시에 key(@id)-value(Entity) 형식으로 저장된다.
- 트랜잭션 커밋 시점에 쓰기 지연 쿼리가 수행된다.
1차 캐시를 이용한 조회
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Customer("명한", "유");
em.persist(customer);
transaction.commit();
Customer foundCustomer = em.find(Customer.class, 1L);
- 영속성 컨텍스의 1차 캐시에 customer가 있기 때문에 DB에 질의하지 않고 1차 캐시에서 바로 결과를 반환한다.
DB를 이용한 조회
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Customer("명한", "유");
em.persist(customer);
transaction.commit();
em.clear();
Customer foundCustomer = em.find(Customer.class, 1L);
- 영속성 컨텍스트를 초기화 해서 1차 캐시에 customer가 없기 때문에 DB에 직접 질의를 해서 결과를 반환한다.
수정
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Customer("명한", "유");
em.persist(customer);
transaction.commit();
transaction.begin();
customer.changeLastName("박");
customer.changeFirstName("은지");
transaction.commit();
- JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해 두는데 이것을 스냅샷이라 한다.
- flush 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾고, 이에 대한 Update Query를 수행한다.
- 변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용이 된다.
삭제
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Customer("명한", "유");
em.persist(customer);
transaction.commit();
transaction.begin();
em.remove(customer);
transaction.commit();
- 트랜잭션 커밋 시점에 Delete Query가 수행된다.
단일엔티티매핑
@Entity
@Table(name = "customers")
public class Customer extends BaseEntity {
@Id @GeneratedValue
private Long id;
@Column(length = 5, nullable = false)
private String firstName;
@Column(length = 2, nullable = false)
private String lastName;
@Enumerated(EnumType.STRING)
private CustomerStatus customerStatus;
@Lob
private String memo;
public Customer() {
}
}
- JPA는 엔티티 객체를 생성할 때, 기본 생성자를 사용한다.
- 왜? reflection API 사용하기 때문에
@Entity
@Table
AUTO DDL 옵션
- create: 기존 테이블을 삭제하고 새로 테이블을 생성
- create-drop: 어플리케이션 종료시 생생한 DDL 제거
- update: 테이블, 엔티티 매핑정보를 비교하여 변경사항 수정
- validate: 테이블, 엔티티 매핑정보를 비교해서 차이가 있으면 어플리케이션을 실행 안함
- none: 자동 생성 기능을 사용 안함
@Column
- name: 필드와 매핑할 테이블의 컬럼 이름
- nullable(DDL): null 값 허용 여부 설정
- unique(DDL): 해당 컬럼의 유니크 제약조건 추가
- length(DDL): 문자 길이 제약조건으로 사용 (String 타입에만 사용)
기본키 매핑전략
- @Id만 사용해서 직접 할당
- @Id와 @GeneratedValue를 통해 자동 할당
- @GeneratedValue 종류
- SEQUENCE
- 데이터베이스 시퀀스에서 식별자 값을 획득(조회)한 후 영속화
- ORACLE, H2
- TABLE
- 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속화
- IDENTITY
- 데이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후 영속화
- 엔티티가 영속화 되려면 식별자 값이 반드시 필요하기 때문에 em.persist() 시점에 INSERT 쿼리가 수행됨
- Mysql (AUTO_INCREMENT)
- AUTO
- 데이터 베이스 방언(dialect)에 따라서 자동으로 전략 선택
기타 컬럼매핑
- @Enumerated(EnumType.STRING)
- @Lob