트랜잭션 범위의 영속성 컨텍스트
순수하게 J2SE 환경에서 JPA를 사용하면 개발자가 직접 엔티티 매니저를 생성하고 트랜잭션도 관리해야 한다.
하지만 스트링이나 J2EE 컨테이너 환경에서 JPA를 사용하면 컨테이너가 제공하는 전략을 따라야 한다.
스프링 컨테이너의 기본 전략
스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.
이 전략은 이름 그대로 트랜잭션의 범위와 영속성 컨텍스트의 생존 범위가 같다는 뜻이다. 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고 트랜잭션이 끝날 때 영속성 컨텍스트를 종료한다.
그리고 같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다.
스프링 프레임워크를 사용하면 보통 비즈니스 로직을 시작하는 서비스 계층에 @Transactional 어노테이션을 선언해서 트랜잭션을 시작한다. 외부에서는 단순히 서비스 계층의 메소드를 호출하는 것처럼 보이지만 이 어노테이션이 있으면 호출한 메소드를 실행하기 직전에 스프링 트랜잭션 AOP가 먼저 작동한다.
스프링 트랜잭션 AOP는 대상 메소드를 호출하기 직전에 트랜잭션을 시작하고, 대상 메소드가 정상 종료되면 트랜잭션을 커밋하면서 종료한다.
트랙잭션을 커밋하면 JPA는 먼저 영속성 컨텍스트를 플러시해서 변경 내용을 데이터베이스에 반영한 후에 데이터베이스 트랜잭션을 커밋한다.
대상 메소드가 정상적으로 종료되면 영속성 컨텍스트의 변경 내용이 데이터베이스에 정상 반영(플러시)되고, 예외가 발생하면 트랜잭션을 롤백하고 플러시를 호출하지 않는다.
트랜잭션이 같으면 같은 영속성 컨텍스트를 사용한다.
트랜잭션 범위의 영속성 컨텍스트 전략은 다양한 위치에서 엔티티 매니저를 주입받아 사용해도 트랜잭션이 같으면 항상 같은 영속성 컨텍스트를 사용한다.
그럼 반대로 트랜잭션이 다르면 어떻게 될까?
트랜잭션이 다르면 다른 영속성 컨텍스트를 사용한다.
반대로 당연히 트랜잭션이 다르면 다른 영속성 컨텍스트를 사용한다.
스프링 컨테이너는 스레드마다 각각 다른 트랜잭션을 할당하기 때문에 같은 엔티티 매니저를 사용해도 트랜잭션이 다르다. 따라서 영속성 컨텍스트가 다르므로 멀티스레드 상황에 안전하다.
스프링이나 JEE 컨테이너의 가장 큰 장점은 트랜잭션과 복잡한 멀티스레드 상황을 컨테이너가 처리해준다는 점이다.
따라서 개발자는 싱글스레드 애플리케이션처럼 단순하게 개발할 수 있고 결과적으로 비즈니스 로직 개발에 집중할 수 있다.