WEB/JPA

김영한 (ORM 표준 JPA 프로그래밍 3) 영속성 관리 - 내부 동작방식

Tony Lim 2021. 2. 25. 10:15
728x90

 

요청이 올떄마다 EntityManager 를 생성해서 dbconnection 을 사용한다.

영속성 컨텍스트 = 엔티티를 영구 저장하는 환경, 논리적인 개념

EntityManager 를 통해 영속성 컨텍스트에 접근이 가능하다.

 

엔티티의 생명주기

비영속(new/transient) = 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태

영속(managed) = 영속성 컨텍스트에 관리되는 상태

준영속(detached) = 영속성 컨텍스트에 저장되었다가 분리된 상태

삭제(removed) = 삭제된 상태

 

장점

1차 캐시

굳이 database까지 안가고 1차캐시에 존재하면 바로 조회하여 네트워크 리소스를 아낄수 있다는 장점이 있다. 만약 없다면

1차캐시에 저장한 후에 반환을 하게 된다. 하지만 애플리케이션 전체에서 공유하는 캐시가 아니다. 그건 2차캐시이고 1차 캐시는 transaction이 끝나면 영속 컨텍스트가 사라짐과 동시에 같이 사라지기에 크게 성능향상에 도움을 주지 않는다.

 

동일성 보장

1차 캐시로 반복가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공

 

트랜잭션을 지원하는 쓰기지연

커밋하는 순간 데이터베이스에 INSERT SQL 을 보낸다. 그전까지는 em.persist 해도 JPA가 1차캐시에 저장하고 엔티티를 분석해서 쓰기 지연 SQL 저장소에 저장한다. 이후 커밋을 하면 DB로 제대로 저장된다.

JDBC batch 같은 hibernate.jdbc.batch_size 의 옵션을 주면 버퍼링같은 기능을 제공 해준다. DB에 한번 쫘악 보내준다. 

 

변경 감지 (Dirty Checking)

커밋을 하면 내부적으로 flush를 호출한다. 그후 엔티티와 스넵샷(값을 읽어온 최초시점)을 비교한다. 그후 달라진게 있으면 UPDATE SQL을 생성한다.

항상 트랜잭션 내에서 entity의 필드 값이 변경이되면 update 쿼리가 날라간다고 생각을 해야한다.

 

플러쉬 = 영속성 컨텍스트의 변경내용을 데이터베이스에 반영, 영속성 컨텍스트를 비우는게 아님

  • 변경감지(Dirty Checking) 
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

1차 캐시를 비우는것이 아니라 쓰기 지연 SQL저장소가 DB에 반영이 되는것이다.

commit 되어야만 실제로 db에 반영되는것이다. 안그러면 rollback 될 것이다. 

JPQL을 실행하면 미연의 문제를 방지하고자 flush() 를 호출해버린다. 안그러면 위의예시에서는 아무 멤버도 조회가 안될것이다.

또한 JPQL로 실행시 바로 DB에서 가져온후 1차 캐시에 저장을 해준다. 왜냐하면 em.find(식별자) 경우 1차 캐시에 있는지 판별하기가 쉬운데 JPQL 처럼 광범위하게 데이터를 찾으면 1차 캐시에서 찾는과정을 구현하기가 어렵기 때문이다.

플러쉬 모드 옵션 = FlushModeType.COMMIT = 커밋할 때만 플러시 , FlushModeType.AUTO = 커밋이나 쿼리를 실행할때 플러시 (기본값)

 

준영속 상태 

영속상태의 엔티티가 영속성 컨텍스트에서 분리(detached)

영속성 컨텍스트가 제공하는 기능을 사용 못함

em.detach(entity) = 특정 엔티티만 준영속 상태로전환

em.clear() = EntityManager 안에 있는것을 통채로 날려버린다 초기화.

em.close() = 영속성 컨텍스트를 완전히 닫아버린다.

 

 

 

 

728x90