- Hibernate ORM
- JPA에서 정의해둔 인터페이스를 구현한 구현체
- JAP에서 지원하는 기능 이외에 Hibernate 자체적으로 사용할 수 있는 API도 지원
데이터 액세스 계층의 상단에 위치
데이터 저장, 조회 등의 작업은 JPA를 거쳐 JPA의 구현체인 Hibernate ORM을 통해서 이루어지며 Hibernate ORM은 내부적으로 JDBC API를 이용해서 데이터베이스에 접근
영속성. 무언가를 금방 사라지지 않고 오래 지속되게 한다.
영속성 컨텍스트
✔ JPA API를 사용하기 위한 사전 준비
- build.gradle 설정
- JPA 설정
- (1) 설정을 추가하면 JPA에서 사용하는 엔티티 클래스를 정의하고 애플리케이션 실행 시, 엔티티와 매핑되는 테이블을 데이터베이스에 자동 생성
- (2) JPA API를 통해서 실행되는 SQL쿼리를 로그로 출력
✔ 샘플 코드 실행을 위한 Configuration 클래스 작성
- (1)과 같이 애너테이션을 추가하면 Spring에서 Bean 검색 대상인 Configuration 클래스로 간주해서 (2) @Bean 애너테이션이 추가된 메서드를 검색하여 해당 메서드에서 리턴하는 객체를 Spring Bean으로 추가해 준다.
- (3)과 같은 CommandLineRunner 객체를 람다표현식으로 정의해주면 애플리케이션 부트스트랩 과정이 완료된 후에 람다 표현식에 정의한 코드를 실행해준다.
✔ 영속성 컨텍스트에 엔티티 저장
- @Entity 애너테이션과 @Id 애너테이션을 추가하면 JPA에서 해당 클래스를 엔티티 클래스로 인식
- (3)
@GeneratedValue
애너테이션은 식별자를 생성해주는 전략을 지정할 때 사용
- 식별자에 해당하는 멤버 변수에 추가하면 데이터베이스 테이블에서 기본키가 되는 식별자를 자동 설정
- Member 엔티티클래스의 객체를 JPA의 영속성 컨텍스트에 저장하는 예제
- JPA의 영속성 컨텍스트는
EntityManager
클래스에 의해 관리, 이 클래스의 객체는 (1) 과 같이EntityManagerFactory
객체를 Spring으로부터 DI 받을 수 있음.- (2)
EntityManagerFactory
의createEntityManager()
메서드를 이용해EntityManager
클래스의 객체를 얻을 수 있음. 객체를 통해서 JPA의 API 메서드 사용 가능- (3) 과 같이
persist(member)
메서드 호출하면 영속성 컨텍스트에 member객체의 정보들 저장됨.- (4) 영속성 컨텍스트에 member객체가 잘 저장되었는지 find 메서드로 조회
- 첫 번째 파라미터는 조회 할 엔티티 클래스의 타입
- 두 번째 파라미터는 조회 할 엔티티 클래스의 식별자 값
em.persist(member)
를 호출하면 1차 캐시에 member 객체가 저장, 이 객체는 쓰기 지연 SQL 저장소에 INSERT 쿼리 형태로 등록- 실제 테이블에 회원 정보를 저장하지는 않음.
✔ 영속성 컨텍스트와 테이블에 엔티티 저장
- (1)
EntityManager
를 통해서Transaction
객체를 얻는다. JPA에서는 이 트랜잭션 객체를 기준으로 데이터베이스의 테이블에 데이터를 저장한다.- JPA에서는 (2)와 같이 트랜잭션을 시작하기 위해서
tx.begin()
메서드를 먼저 호출- (3) member 객체를 영속성 컨텍스트에 저장
- (4)
tx.commit()
을 호출하는 시점에 컨텍스트에 저장된member
객체를 데이터베이스의 테이블에 저장한다.- (5)
em.find(Member.class, 1L)
호출하면 컨텍스트에 저장한member
객체를 1차 캐시에서 조회
- 1차 캐시에 member 객체 정보가 있으므로 별도로 테이블에 SELECT 쿼리 전송x
- (6)
em.find(Member.class, 2L)
호출해서 식별자 값이 2L 인 member 객체를 조회
컨텍스트에 객체가 존재하지 않으므로 (7) 의 결과는 true
- (6) 에서 컨텍스트에서 2L 객체가 존재하지 않으므로 테이블에 직접 SELECT 쿼리 전송
tx.commit()
을 했기 때문에 member 에 대한 INSERT 쿼리가 실행되어 쓰기 지연 SQL 저장소에서 사라진다.
- SELECT 쿼리 실행됨.
em.persist()
호출 시 영속성 컨텍스트의 1차 캐시에 엔티티 클래스 객체 저장, 쓰기 지연 SQL 저장소에 INSERT 쿼리가 등록tx.commit()
을 하는 순간 쓰기 지연 SQL저장소에 등록된 INSERT 쿼리 실행, 실행된 쿼리는 저장소에서 제거em.find()
를 호출하면 먼저 1차 캐시에서 해당 객체가 있는지 조회, 없으면 테이블에 SELECT 쿼리를 전송해서 조회✔ 쓰기 지연을 통한 영속성 컨텍스트와 테이블에 엔티티 일괄 저장
tx.commit()
을 하기 전까지는 SQL 저장소에 등록된 INSERT 쿼리가 실행되지 않음.
(테이블에 데이터 저장 x)tx.commit()
이 실행된 이후에는 INSERT 쿼리가 모두 실행. 테이블에 데이터 저장됨.
✔ 영속성 컨텍스트와 테이블에 엔티티 업데이트
- (1)에서 member 객체를 영속성 컨텍스트의 1차 캐시에 저장
- (2) 에서 tx.commit() 호출해서 컨텍스트의 쓰기 지연 SQL 저장소에 등록된 INSERT 쿼리 실행
- (3) 과 같이 (2)에서 테이블에 저장된 member객체를 영속성 컨텍스트의 1차 캐시에서 조회
(테이블에서 조회하는것이 아님) 이미 1차캐시에 저장되어있음.- (4) setter 메서드로 이메일 변경
- (5)
tx.commit()
을 실행하면 쓰기 지연 SQL 저장소에 등록된 UPDATE 쿼리가 실행된다.
- UPDATE 쿼리 실행 과정
영속성 컨텍스트에 엔티티가 저장될 경우에는 그 시점의 상태를 그대로 가지는 스냅샷 생성
엔티티 값을 setter로 변경 후 커밋을 하면 변경된 엔티티와 스냅셧 비교후 변경된 값이 있으면 UPDATE 쿼리를 등록하고 실행함.
✔ 영속성 컨텍스트와 테이블의 엔티티 삭제
- (1) Member 클래스의 객체를 영속성 컨텍스트의 1차 캐시에 저장
- (2) 커밋을 호출해서 INSERT 쿼리 실행
- (3) 영속성 컨텍스트의 1차 캐시에서 조회
- (4) em.remove(member) 를 통해 1차 캐시에 있는 엔티티 제거 요청
- (5) 1차 캐시에 있는 엔티티 제거 후 , SQL 저장소에 등록된 DELETE 쿼리 실행
- tx.commit() 메서드가 호출되면 JPA 내부적으로 em.flush() 메서드가 호출되어 변경 내용을 데이터 베이스에 반영