1. JPA
ORM
이며 객체 지향과 데이터베이스 간 발생하는 차이를 매핑해줌
- 객체는 객체대로 설계가 가능하고, DB와의 차이점에 대해서는 ORM을 통해서 매핑
- SQL 중심적 개발에서
객체 중심적 개발
을 할 수 있게 되어 데이터베이스에 종속적이지 않게 됨
- JPA는
JDBC API
를 통해서 DB에 접근하고, java application
과 JDBC API
사이에 존재함
- JPA는 인터페이스의 모음이고,
hibernates
는 그 구현체임
Entity
는 DB 테이블과 매핑되는 객체
2. EntityManager
1) EntityManagerFactory
EntityManger
를 만들고 구성하는 법을 제공하는 interface
- JPA의 구현체인 Hibernate나 EclipseLink에 의해서 생성
2) EntityManager
- DB table과 매핑된 객체인
Entity
에 대한 CRUD
작업을 수행하기 위한 메서드를 제공
- 엔티티의 라이프 사이클과 영속성 관리를 담당함
- Entity Manager는 영속성 컨텍스트에 entity를 보관하고 관리함
3. PersistenceContext
Persistence(영속성)
- 데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지 않는 데이터의 특성
- 특정 데이터 구조를 이전 상태로 복원할 수 있게 해줘서 프로그램의 종료와 재개를 자유롭게 해줌
EntityManger.persist
EntityManger.persist(entity)
- 위 코드처럼
EntityManger
를 통해서 영속성 컨텍스트에 접근하게 됨
- 해당
entity
를 영속성 컨텍스트로 보내고 영속성 컨텍스트를 통해서 해당 데이터를 영속화 함
4. 1차 캐시, 동일성 보장
- 영속성 컨텍스트는
entity
를 식별자 값으로 구분함
Entity
에 @Id
annotation을 통해 지정한 멤버 변수가 영속성 컨텍스트에 식별자 값으로 저장됨
- JPA는 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된
entity
를 DB에 반영함(이 과정을 flush라고 함)
- 영속성 컨텍스트 내부에 존재하는 캐시(Map)을
1차 캐시
라고 하는데, 영속 상태의 entity
는 모두 1차 캐시에 저장됨
- 키는
@Id
로 매핑한 식별자이며, 값은 entity instance
find()
메서드를 호출하면 1차 캐시에서 먼저 엔티티를 찾음
- 찾는 엔티티가 1차 캐시에 없으면 디비에서 조회한 후 1차 캐시에 저장함
- 그리고 영속 상태인 해당 객체를 반환함
- 1차 캐시에 있는 같은 엔티티 인스턴스를 반환하기 때문에 엔티티의 동일성을 보장함
5. Transactional write-behind(쓰기 지연)
- 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 디비에 엔티티를 저장하지 않고, 영속성 컨텍스트 내부의 SQL 저장소에 생성 쿼리를 저장함
- 이후에 커밋을 하게 되면 저장했던 쿼리를 디비에 보냄
- 트랜잭션을 커밋하면 엔티티 매니저는 영속성 컨텍스트를
flush()
함
flush()
: 영속성 컨텍스트의 변경 내용을 디비에 동기화하는 작업
- 생성/수정/삭제한 엔티티를 디비에 반영함
6. Lazy Loading(지연로딩)
- 실제 객체 대신 프록시 객체를 로딩
- 해당 객체를 사용할 때 영속성 컨텍스트를 통해 데이터를 불러옴
Member member = memberDAO.find(memberId);
Team team = member.getTeam();
String teamName = team.getName();
- 첫 번째 라인에서는
Member
객체에 대한 Select 쿼리를 날리기만 함
- 두 번째 라인에서
Team
객체를 가져오고, 세 번째 라인에서 Team 객체를 실제로 사용할 때 즉, name
이라는 값이 실제로 필요한 시점에 JPA가 Team에 대한 Select
쿼리를 실행함
- 이때
Member
와 Team
객체를 각각 따로 조회하기 때문에 네트워크를 2번 타서 지연 로딩
이라고 함
- 만약 Member와 Team을 같이 필요로 한다면
즉시 로딩
을 사용하면 됨