[Qdsl, JPA] @PersistenceContext 의 역할

개요

  • Java Persistence API ( JPA ) 의 일부이다.
  • 컨테이너 관리형 영속성 컨텍스트에 대한 EntityManager 주입의 역할을 수행한다.

영속성 컨텍스트의 역할

  • 엔티티 인스턴스의 생명주기를 관리한다.
  • DB와 상호작용을 담당한다.

사용은 언제하나?

  • DAO(서비스 레이어) 혹은 Repository 계층에서 사용한다.

해당 어노테이션 역할

  • JPA 영속성 컨텍스트에 접근하기 위해 사용되는 EntityManager를 주입받기 위해 사용된다.
  • Spring Framework 에서 해당 어노테이션을 통해 컨테이너가 관리하는 EntityManager 를 Service 레이어 혹은 레포 레이어에 제공

이점

  1. 자원의 관리
    • DB 연결을 효율적으로 ㄱㄴ
  1. 트랜잭션의 관리
    • 트랜잭션 범위에서 영속성 컨텍스트를 제공한다.
  1. Thread Safe
    • 컨테이너가 EntityManger 를 관리하여 스레드에 안전함

그럼 어디서 EntityManager 를 관리하는지 찾아보자

  • 일단 SharedEntityManagerCreator.class 를 찾아보자
    • 이는 Jpa 라이브러리의 일부로서..
    • 관련 주제로 PersistenceContext 가 존재함으르 알 수 있다.
    • 한글로 번역하니
    • 즉, em 이 존재하는 경우 해당 em 을 사용하고, 존재하지 않는 경우 새로 생성된 em 을 사용함을 알 수 있다.

해당 클래스에서 EntityManager의 프록시 생성하는 곳은.

/**
	 * Create a transactional EntityManager proxy for the given EntityManagerFactory.
	 * @param emf the EntityManagerFactory to obtain EntityManagers from as needed
	 * @param properties the properties to be passed into the
	 * {@code createEntityManager} call (may be {@code null})
	 * @param synchronizedWithTransaction whether to automatically join ongoing
	 * transactions (according to the JPA 2.1 SynchronizationType rules)
	 * @param entityManagerInterfaces the interfaces to be implemented by the
	 * EntityManager. Allows the addition or specification of proprietary interfaces.
	 * @return a shareable transactional EntityManager proxy
	 * @since 4.0
	 */
	public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties,
			boolean synchronizedWithTransaction, Class<?>... entityManagerInterfaces) {

		ClassLoader cl = null;

		if (emf instanceof EntityManagerFactoryInfo) {
			cl = ((EntityManagerFactoryInfo) emf).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));
	}
  • 요 부분이다.
    • SharedEntityManagerInvocationHandler 요 부분은 실제로 메서드 호출을 처리하는 내부 클래스로서,
    • TransactionSynchronizationManager를 사용해 현재 스레드와 관련된 EM 를 찾고, 해당 EM 에 대한 모든 작업을 수행
      public abstract class TransactionSynchronizationManager {
          // ...
          private static final ThreadLocal<Map<Object, Object>> resources =
                  new NamedThreadLocal<>("Transactional resources");
      
          public static Object getResource(Object key) {
              Object value = doGetResource(key);
              if (value != null && logger.isTraceEnabled()) {
                  logger.trace("Retrieved value [" + value + "] for key [" + key + "] bound to thread [" +
                          Thread.currentThread().getName() + "]");
              }
              return value;
          }
          // ...
      }
      • 각 스레드가 자신만의 EM 인스턴스를 가지고 작업하도록 보장.
        • 해당 key 값을 조회하여 스레드내의 EM 존재여부를 파악하는 식으로 수행되는 것 같다.

Uploaded by N2T