본문 바로가기

JPA

[JPA] JPA 영속성 컨텍스트

JPA를 사용하면, EntityManagerFactory에서 EntityManager를 얻고, EntityManager를 이용해, DB관련 작업을 처리한다. EntityManager는 영속성 컨텍스트를 만드는데, 영속성 컨텍스트는 엔티티를 저장하고, 관리하는 등의 역할을 한다.

 

영속성 컨텍스트

영속성 컨텍스트를 사용하면, 다음 이점이 있다.

1. 1차캐시 

2. 동일성 보장

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

4. 변경감지

5. 지연로딩

 

1차캐시

영속성 컨텍스트는 내부에 캐시를 갖고있다.

DB에 flush를 하기위해, 영속성 컨텍스트에 persist한 엔티티나 DB에서 가져온 엔티티를 저장하며, 해당 엔티티를 "영속화"상태로 만든다.

영속화 상태인 엔티티는 영속성 컨텍스트에 의해 관리되며 많은 이점을 누릴 수 있다.

영속성 컨텍스트가 지원하는 1차캐시는, 내가 찾을려는 엔티티가 "영속화" 상태라면, DB에 쿼리를 날리지않고, 영속성 컨텍스트 내에서 엔티티를 반환한다. 

동일성 보장

영속성 컨텍스트의 1차캐시를 통해 반환된 엔티티는 동일성을 보장한다.

데이터베이스는 아이디값을 기준으로 엔티티의 동일성을 구분하는반면, 자바(객체지향 패러다임언어를 여기서는 자바라고 하겠다.)는 주솟값을 기준로 엔티티를 구분한다. 따라서, 데이터베이스 상에서 동일한 엔티티여도 객체에서는 동일성 비교를 실패할 수 있다.

예를들어, 직접 DB에 쿼리를 날려 같은 아이디의 엔티티를 두번 가져왔을때, 이 두 엔티티는 동등하지만 동일하지는 않다. 따라서, 동일성 비교(== 비교)는 실패하게되는데, 영속성 컨텍스트를 이용하면 이러한 패러다임의 차이에서 나오는 문제점을 해결해준다.

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

영속성 컨텍스트는 트랜잭션을 커밋하기 전까지 INSERT SQL를 영속성 컨텍스트에 모아두고, 트랜잭션을 커밋할때, 모인 INSERT SQL을 한번에 플러시 한다. 

네트워크와 통신하는것은 상당히 많은 비용이 든다. 영속성 컨텍스트의 쓰기 지연을 활용하면, 네트워크 통신을 최소화하여 INSERT SQL을 날릴수 있으며, 데이터베이스 로우에 락이 걸리는 시간또한 최적화 시킬 수 있다.

변경감지

영속성 컨텍스트는 영속상태인 엔티티의 변경을 감지한다.

엔티티는 처음 영속화 될때, 최초 상태가 복사되어 저장되는데 이를 스냅샷 이라고 한다. 이후 엔티티를 플러시 할때, 스냅샷과 변경된 값을 비교하여, 변경된 엔티티를 찾는다. 

변경감지는 영속상태인 엔티티에 대해서만 적용되는데 이 말은 곧, 트랜잭션 범위 밖에서는 변경감지 기능이 적용되지 않는다는 것을 뜻한다. (트랜잭션 범위 밖이라면 어떠한 경우라도 준영속 상태 일 것 이므로)

때문에, 트랜잭션 범위 밖에서 준영속 상태의 엔티티를 수정하고 DB값의 변경을 기대하는(혹은 지연로딩을 할 수 없는) 실수를 흔히 할 수 있는데, 이러한 문제의 해결법에 대해서는 차후 서술하도록 하겠다.

지연로딩

영속성 컨텍스트는 프록시 객체를 이용해 엔티티를 지연로딩 할 수 있게 해준다.

엔티티 A와 엔티티 B가 일대다 연결관계라고 가정해보자. 엔티티 A의 정보만 필요한 상황에서 엔티티 B를 같이 로딩 하여 메모리에 올리는것은 비효율적이다. 따라서, 영속성 컨텍스트는 지연로딩을 통해 해당 엔티티가 실제 호출될때 로딩하는 방법을 제공한다.