CH02 JPA 시작

2장은 책의 목차와 내용이 생각보다 부실하고 오히려 인프런 강의가 정리가 잘 되어있어서, 강의 중심으로 정리한다.

JPA에서 알아서 처리해주는 트랜잭션을 코드로 구현해보기

편리한 기능을 제공해준다고 해서 결과만 인식하고 사용하다보면 원리를 깊게 이해하기도 어렵고 문제가 발생 했을때 원인을 찾을 내공이 부족하게 된다.

@Transactional 을 이용해서 한 단위의 트랜잭션으로 묶어서 처리를 하곤 하는데 이렇게 어노테이션으로 트랜잭션 단위를 정하는 행위가 실제 내부적으로 어떻게 처리가 되는 것인지에 대해 알 수 있도록 raw 한 수준에서 코드로 작성해보는 기회가 되었다.

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistenceUnitName");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();

try {
    transaction.begin();
    
    // business logic
    
    transaction.commit();
} catch (Exception exception) {
    transaction.rollback();
} finally {
    entityManager.close();
}

핵심은 트랜잭션의 시작과 커밋이 try 내에 존재한다는 것이다. 예외 발생시 catch 에서 롤백이 된다. 어노테이션에서 어떤 예외일때 롤백할지도 정할 수 있는데 그런 경우에는 여기서 catch 가 조금 더 세분화가 될 것이다.

나중에 백기선님 강의나 김영한님 강의에서도 계속 다루고 있는데, EntityManager 는 스레드에 따라 독립적으로 할당된다. (이 부분은 아래에 다시 정리)

JPA 구성요소간 관계도

외울 것도 없고 흐름에 맞춰서 생각해보면 당연한 내용들이다. Persistence Unit 은 아래와 같이 Database 접속 정보를 가지고 있는 configuration 이라고 보면 된다.

위 구조에서 entityManagerFactory의 경우 Bean으로 자동 생성된다. Runner 에서 아래와 같이 직접 확인해본다.

EntityManager 는 @PersistenceContext 를 통해서 아래와 같이 entityManagerFactory 로 생성해서 주입받아 사용한다. 하지만 실무에서는 굳이 직접 EntityManager 를 사용할 일은 적어도 나의 경험 선에서는 없었다.

책에서도 강조하듯 EntityManager는 데이터 베이스 커넥션과 밀접하게 작동하므로 스레드간에 공유하거나 재사용을 하면 안된다. 아래와 같이 EntityManager 를 변수명을 달리 하여 두 개를 생성해봐도 결국 주소값을 비교해보면 동일한 EntityManager 임을 확인할 수 있다.

결국 entityManagerFactory 만 빈으로 주입받아고 여기서 스레드마다 별도로 entityManager 를 할당 받고 이 entityManager 가 위에서 원형 코드를 본 것처럼 트랜잭션을 관리하기 때문에 1개의 트랜잭션을 만들고 이것을 try 내에서 시작 후 커밋까지 한다. catch 에서 롤백이 발생하며 결과가 어떻게 되든 finally 에서 리소스를 반환한다.

Last updated