본문 바로가기

Development/DB, JPA

스프링 JPA 그리고 LazyInitializeException

1. 스프링 컨테이너의 기본전략

스프링 컨테이너를 사용하면, 컨테이너가 트랜잭션과 영속성 컨텍스트를 관리해준다. 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.

이는 다음을 의미한다.

트랜잭션의 범위 = 영속성 컨텍스트의 생존 범위

즉 , 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고, 트랜잭션이 종료될 때 영속성 컨텍스트를 종료한다

2. @Transactional 어노테이션

@Transactional을 통해 동작하는 스프링 트랜잭션 AOP는 대상 메소드를 호출하기전에 트랜잭션을 시작하고 메소드가 종료되면 커밋을 하면서 종료한다. 이때 트랜잭션을 커밋하기 직전 JPA는 영속성 컨텍스트를 플러시해서 변경 내용을 데이타베이스에 반영한다.

  • 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고, 트랜잭션이 종료될 때 영속성 컨텍스트를 종료한다.

  • 같은 트랜잭션 내에서는 같은 영속성 컨텍스트를 사용한다.

  • 트랜잭션은 보통 서비스 계층에서 시작한다.

3. 트랜잭션이 종료되면 준영속상태가 된다.

서비스 계층이 끝나는 시점에 트랜잭션이 종료되면서 영속성 컨텍스트도 함께 종료된다. 트랜잭션이 종료되는 프레젠테이션 계층(ex. 컨트롤러)에서는 준영속상태가 된다.

준영속 상태에서는 변경감지와 지연로딩이 동작하지 않는다.

사실 변경감지가 동작하지 않는 것은 맞다고 생각한다. 레이어가 분리된 만큼 역할과 책임이 분리되어야 하기 때문에 프레젠테이션 계층에서 데이타 변경에 대한 책임은 없다. 문제는 지연로딩이다.

지연로딩이 동작하지 않는 예

@Controller public class MemberController{ @Autowired private MemberService memberService; public String test(){   Member member = memberService.getMember(1L); // 서비스 내에서 트랜잭션이 열리고 닫힌다.   Team team = member.getTeam();   String teamName = team.getTeamName(); // Lazy Exception 발생 !!       ... } }

지연로딩이 동작하지 않는 문제를 해결하는 방법

  • 뷰가 필요한 엔티티를 미리 다 로딩한다.

  • OSIV - Open Session In View


'Development > DB, JPA' 카테고리의 다른 글

DBCP maxLIfeTime Issue  (0) 2020.02.09
Lazy Initialize Exception 방어코드  (0) 2017.03.27
NULL 제약 조건과 조인 전략  (0) 2017.03.21
JPA를 이용한 다대일 객체 관계 매핑  (0) 2017.03.17
JPA 기본 키 전략  (0) 2017.03.12