JPA를 사용하여 CRUD 프로그램을 구현하는데 사용되는 API들과 엔티티의 상태 및 라이프 사이클
JPA가 EntityManager 객체를 얻기까지의 과정
EntityManager를 얻은 후에는, 이 객체를 이용하여 CRUD 작업을 진행하면 된다. 다만 주의할 점은 등록, 수정, 삭제 작업은 반드시 트랜잭션 내에서 끝내주는 것
EntityManager가 제공하는 CRUD 기능의 메소드
| 메소드 | 기능 |
|---|---|
| persist(Object Entity) | 엔티티 영속화 insert |
| merge(Object Entity) | 준영속 상태의 엔티티 영속화 update |
| remove(Object Entity) | 영속 상태의 엔티티 제거 delete |
| find(Class entityClass, Object pk) | 하나의 엔티티 검색 select one |
| createQuery(String jpql, Class resultClass) | JPQL에 해당하는 엔티티 목록 검색 select list |

영속성 컨텍스트
EntityManager = 영속성 컨텍스트라고 생각하면 됨
영속성 컨텍스트에 등록된 엔티티가 가지는 상태는 아래와 같다
persist(), find()detach(), clear(), close()merge() 메소드를 통해 다시 영속 상태로 전환 가능remove()영속성 컨텍스트는 내부에 1차 캐시를 가지고 있다. 1차 캐시는 일종의 Map과 같은 컬렉션으로 Key와 Value로 엔티티를 관리한다.
이 때 Key 값은 @Id로 매핑한 식별자 값이고 Value값은 엔티티 객체가 된다.
persist() 를 통한 엔티티 영속화@Id : 엔티티 객체)이 때 중요한 점은 1차 캐시에 저장된 엔티티는 바로 실제 데이터베이스에 반영되지 않고, EntityTransaction의 commit()으로 트랜잭션을 종료할 때 실제로 반영된다는 것
이렇게 영속성 컨텍스트에 저장된 엔티티를 데이터베이스에 반영하는 과정을 Flush라고 한다.
영속성 컨텍스트는 내부에 1차 캐시뿐만 아니라 SQL 저장소도 가진다
영속성 컨텍스트에 엔티티를 persist() 하여 저장하면 영속성 컨텍스트는 두 가지 작업을 순차적으로 처리한다.
이렇게 계속 새로운 엔티티를 누적하다가 commit()메소드를 통해 트랜잭션을 종료하면 SQL 저장소에 저장했던 모든 SQL을 한번에 데이터 베이스로 전달한다.
→ 성능 최적화
엔티티를 검색한 후, 검색된 엔티티를 수정한다고 가정한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ex01");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Board board = em.find(Board.class, 1L);
board.setTitle("Changed Title");
tx.commit();
JPA는 검색된 엔티티를 영속성 컨텍스트에 저장 시, 엔티티의 복사본을 만들어서 별도의 컬렉션에 저장하는데 이 저장공간을 스냅샷이라고 한다.
트랜잭션이 종료될 때 스냅샷에 저장된 원래의 엔티티와 1차 캐시에 수정된 엔티티를 비교하여서 UPDATE 작성하여 이를 SQL 저장소에 저장된 다른 SQL들과 함께 전송한다.
remove() 메소드로 엔티티 삭제 시
테이블에 저장된 특정 데이터의 상세 조회 → find()
목록 조회 → JPQL(Java Persistence Query Language) 이라는 JPA에서 제공하는 별도의 쿼리 명령어 사용
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ex01");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
String jpql = "SELECT b FROM Board b order by b.seq desc";
List<Board> list =
em.createQuery(jpql, Board.class).getResultList();
for(Board board : list) {
System.out.println(board.toString());
}
JPQL의 검색대상은 테이블이 아니라 엔티티이다
검색대상이 엔티티이기 때문에 엔티티 이름과 엔티티가 가지고 있는 변수를 사용하여 쿼리를 구성해야한다.