스레드는 서버에 요청을 보낸 사용자와 같다.
난 이 때 까지 JPA를 사용할 때, 하나의 스레드 당 하나의 영속성 컨텍스트를 부여받는다고 생각했다.
그런데 자바 ORM 표준 JPA 프로그래밍의 15장에서 이 문장을 읽고 머리가 아파졌다.
문제는 OSIV처럼 영속성 컨텍스트의 범위를 트랜잭션 범위보다 넓게 사용해서 여러 트랜잭션이 하나의 영속성 컨텍스트를 사용할 때 발생한다.
- 15장, 645페이지
하지만 스레드와 영속성 컨텍스트의 관계에 대한 정보를 찾아보니까, 아래의 답변 또한 찾을 수 있었다.
영속성 컨텍스트는 스레드마다 독립적으로 생성되며, 스레드 간에 공유되지 않습니다. 따라서 개별 스레드에서 동작하는 엔티티 매니저는 각자 독립된 영속성 컨텍스트를 가지게 됩니다.
- 인프런 AI 인턴
내가 생각한 로직은 다음과 같다.
다시 책으로 돌아와서,
"문제는 OSIV처럼 영속성 컨텍스트의 범위를 트랜잭션 범위보다 넓게 사용해서 여러 트랜잭션이 하나의 영속성 컨텍스트를 사용할 때 발생한다."
이 문장을 위의 그림을 토대로 해석하면 다음과 같다.
- 영속성 컨텍스트의 범위를 트랜잭션 범위보다 넓게 사용 -> 영속성 컨텍스트 범위는 프레젠테이션 계층까지 퍼져있는 상태
- 여러 트랜잭션이 하나의 영속성 컨텍스트를 사용 -> 한 컨트롤러에서 트랜잭션이 적용된 2개 이상의 메서드를 각각 호출할 경우, 다른 트랜잭션이 적용된다.
이를 토대로 코드를 작성해봤다.
@Slf4j
@Controller
@RequiredArgsConstructor
public class HomeController {
private final OrderService orderService;
private final MemberService memberService;
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void home() {
log.info("첫번째");
Member findMember = memberService.findById(1L);
log.info("두번째");
Order findOrder = orderService.findById(1L);
}
}
결과 로그는 다음과 같다.
2024-07-31T01:01:48.591+09:00 INFO 82631 --- [nio-8080-exec-1] c.j.ch16.controller.HomeController : 첫번째
2024-07-31T01:01:48.591+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1332011983<open>)] for JPA transaction
2024-07-31T01:01:48.591+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.jpabook.ch16.service.MemberService.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2024-07-31T01:01:48.591+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@84c8cbd]
2024-07-31T01:01:48.595+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2024-07-31T01:01:48.595+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1332011983<open>)]
2024-07-31T01:01:48.595+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
2024-07-31T01:01:48.595+09:00 INFO 82631 --- [nio-8080-exec-1] c.j.ch16.controller.HomeController : 두번째
2024-07-31T01:01:48.595+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1332011983<open>)] for JPA transaction
2024-07-31T01:01:48.596+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.jpabook.ch16.service.OrderService.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2024-07-31T01:01:48.596+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@404463e2]
2024-07-31T01:01:48.596+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2024-07-31T01:01:48.596+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1332011983<open>)]
2024-07-31T01:01:48.596+09:00 DEBUG 82631 --- [nio-8080-exec-1] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
로그를 자세히 살펴보면
첫번째
Found thread-bound EntityManager [SessionImpl(1332011983<open>)] for JPA transaction
Creating new transaction with name [com.jpabook.ch16.service.MemberService.findById]: ..
이 로그의 의미는 스레드에 할당된 엔티티 매니저를 뜻하며 영속성 컨텍스트도 여기에 속하고, 데이터베이스에 접근하기 위해 새로운 트랜잭션을 생성한다. 라는 의미이다.
두번째
Found thread-bound EntityManager [SessionImpl(1332011983<open>)] for JPA transaction
Creating new transaction with name [com.jpabook.ch16.service.OrderService.findById]: ..
이 로그도 위와 동일하다.
여기서 주목해야 할 점은 두 작업은 모두 새로운 트랜잭션을 생성하여 작업을 수행 한다.
하지만 영속성 컨텍스트는 Found thread-bound EntityManager [SessionImpl(1332011983)] 를 보다시피 같은 영속성 컨텍스트를 사용한다.
결론은 영속성 컨텍스트는 요청을 보낸 사용자(스레드) 별로 독립적으로 구성된다. 그렇기 때문에 하나의 영속성 컨텍스트를 사용하는 것 또한 맞는 말이다.
휴 모래성 무너질 뻔!
'Spring > JPA' 카테고리의 다른 글
[JPA] Spring JPA 페이징 성능 향상 (2) | 2024.12.24 |
---|---|
[JPA] @Embedded, @Embeddable (0) | 2024.07.16 |