영속성 컨텍스트는 엔티티를 영구 저장하는 환경이라는 뜻이다. 영속성 컨텍스트는 논리적인 개념이며, EntityManager
를 통해서 영속성 컨텍스트에 접근할 수 있다. J2SE 환경에서는 EntityManager
와 영속성 컨텍스트가 1대1 관계이다.
영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
ex) 객체를 생성하기만 한 상태
영속성 컨텍스트에 관리되는 상태
ex) 생성한 객체를 em.persist()
로 저장한 상태 -> DB에 저장된 것은 아니다.
em.find()
로 영속성 컨텍스트에서 객체를 가져온 상태
영속성 컨텍스트에 저장되었다가 분리된 상태
삭제된 상태
// 비영속
Member member = new Member();
member.setId(100L);
member.setUsername("회원1");
// 영속
em.persist(member);
// 준영속
em.detach(member);
// 삭제
em.remove(member);
JPA에서 객체를 조회할 때는 바로 DB를 조회하는 것이 아니라 1차 캐시에 해당 객체가 있는지부터 확인한다. 만약 1차 캐시에 객체가 있다면 1차 캐시에서 바로 값을 가져온다. 1차 캐시에 찾고자 하는 객체가 없다면, DB에서 값을 가져와 1차 캐시에 저장 후 값을 반환한다. 이후에 다시 해당 객체를 조회한다면 DB를 조회하지 않고 1차 캐시에 저장된 객체를 가져온다. 트랜잭션이 종료될 때 1차 캐시도 함께 지워지기 때문에 큰 성능 차이가 있지는 않다.
같은 트랜잭션 안에서 같은 객체를 조회할 경우 동일성을 보장한다. 1차 캐시로 반복 가능한 읽기(REPEATABLE READ)등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공한다.
jpa는 em.persist(entity)
를 실행할 때 INSERT SQL을 바로 데이터베이스에 보내지 않고, transaction을 commit하는 순간 데이터베이스에 INSERT SQL을 보낸다. em.persist(entity)
를 실행하면 객체를 1차 캐시에 저장하고, INSERT SQL을 생성해 쓰기 지연 SQL 저장소에 저장해둔다. 이후 transaction을 commit할 때 쓰기 지연 SQL 저장소에 있던 SQL문들을 데이터베이스에 보낸다. SQL문을 바로 데이터베이스에 보내는 것이 아니라 모아서 한번에 보내는 버퍼링을 할 수 있기 때문에 성능적으로 이점이 있다.
jpa에서는 update 명령을 따로 호출할 필요가 없다. transaction을 commit하면 현재 entity와 처음 상태의 entity가 저장된 snapshot을 비교한다. entity에 변화가 있을 경우 UPDATE SQL을 생성하여 쓰기 지연 SQL 저장소에 저장하고, 데이터베이스에 SQL문들을 보낸다.
플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것이다. 플러시가 발생하면 다음과 같은 일을 한다.
플러시는 영속성 컨텍스트를 비우는 것이 아니라 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화 하는 것이다. transaction이라는 작업 단위가 중요하며, commit 직전에만 동기화를 하면 된다.
준영속 상태란 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것을 말한다. 준영속 상태에서는 영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.