영속성 컨텍스트는 DB와 어플리캐이션 서버의 중간에서 엔티티를 저장하고 관리하는 역할을 하는 가상의 저장 공간을 말한다. 영속성 컨텍스트는 엔티티 매니저(EntityManager) 접근이 가능하다.
비영속은 엔티티는 생성을 했지만 아직 영속성 컨텍스트에 등록되지 않은 상태로 영속성 컨텍스트에서 관리되지 않는 상태다.
영속 상태는 엔티티 매니저를 통해 영속성 컨텍스트에 등록 된 상태로 엔티티가 영속성 컨텍스트에서 관리되는 상태를 말한다. persist()
로 엔티티를 영속 상태로 만들어 줄 수 있다.
준영속 상태는 영속성 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태를 말한다. detach()
, clear()
, close()
명령어로 영속성 컨텍스트에서 엔티티를 분리할 수 있다. 준영속 상태의 엔티티는 영속 상태의 이점을 누릴 수 없다.
준영속 상태의 엔티티를 다시 영속 상태로 만들려면 merge()
명령어를 사용하면 된다.
삭제 상태는 영속컨 텍스트에서 엔티티를 삭제했지만 아직 DB에는 반영 되지 않은 상태를 말한다. remove()
명령어로 엔티티를 삭제할 수 있다.
영속성 컨텍스트는 쓰레드 세이프 하지 않다. 때문에 영속성 컨텍스트는 쓰레드간에 공유가 되면 같은 엔티티에 접근할 때 정합성의 문제가 생길 수 있다.
하지만 스프링에서 영속성 컨텍스트는 쓰레드 세이프 하다. 이유는 스프링은 엔티티 매니저를 프록시로 생성하면서 쓰레드간 동시접근을 막고있기 때문이다.
public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction, Class<?>... entityManagerInterfaces) {
ClassLoader cl = null;
if (emf instanceof EntityManagerFactoryInfo emfInfo) {
cl = emfInfo.getBeanClassLoader();
}
Class<?>[] ifcs = new Class[entityManagerInterfaces.length + 1];
System.arraycopy(entityManagerInterfaces, 0, ifcs, 0, entityManagerInterfaces.length);
ifcs[entityManagerInterfaces.length] = EntityManagerProxy.class;
return (EntityManager)Proxy.newProxyInstance(cl != null ? cl : SharedEntityManagerCreator.class.getClassLoader(), ifcs, new SharedEntityManagerInvocationHandler(emf, properties, synchronizedWithTransaction));
}
위 코드는 SharedEntityManagerCreator
클래스에서 확인 할 수 있으며 마지막 return 부분을 보면 다이나믹 프록시를 사용하고 매개변수로 스레드세이프를 체크하는 기능이 들어가는 걸 확인 할 수있다.