그 이유는 간단히 말해 트랜젝션단위의 오픈이 없어도 연관관계를 맺고있는 모든객체의 로드가 어.디.에.서.든
가능해지기 때문이다. 현재 내가 맡고있는 현X자동차 프로젝트에 투입되었을시 OSIV 옵션이 true 인 상태로 프로젝트를 진행하면서 지연로딩에 대해 별 생각없이 save 메소드가 있구나 객체의 변경이 많으니 이곳에 트랜젝션 단위가 들어가야 하는구나 하며 진행을 해왔다. 현시점에와 서비스가 커지고 점점 비스니스의 요구사항이 높아짐에 따라 지금까지 위태롭게 달려오던 우리의 현X자동차 어플리케이션은 많은 장애와 위기를 맞고 있어 이 글을통해 정리를 해나가려한다.
JPA 영속성 컨텍스트의 생존 범위는 트랜젝션이 시작하는 시점과 종료되는 시점과 일치한다. 하지만 OSIV 가 동작하고 있다면 영속성컨텍스트의 라이프 사이클은 Api 클라이언트 요청시작부터 응답종료까지 살아있게된다.
영속성 컨텍스트의 생존범위가 하나의 전체 트랜젝션을 아우르고 있어 어디에서든지 지연로딩으로 연관된 엔티티의 조회가 가능해지는 장점이 있다.
영속성 컨텍스트가 종료될때 트랜젝션이 종료되어 쓰기지연 영역의 Sql 문이 플러시 커밋이 이뤄지나 요청이 종료되며 닫히는 영속성 컨텍스트의 쓰기지연 영역은 데이터베이스에 플러시하지 않는다
엔티티 수정반영은 트랜젝션 계층에서만 작동하며 트랜젝션 영역 외 프레젠테이션 계층은 조회만 할 수있다.
얼핏 보면 매우 쓸만한 옵션인듯 보이지만 잘못 사용될 여지가 보인다. 하나씩 열어보자
위 코드에서 3번 아이디를 가진 멤버를 가져오면 3번의 아이디를 가진 데이터의 이름은 현재 스폰지밥이다.
Test 메소드가 종료될때 최종적으로 디비에 종료되는 이름은 무엇일까 트랜젝션 내부에서 변경된 Cellar 일까 아니면 마지막으로 바뀐 이름인 Patrick일까. 결론은 Patrick 으로 최종 디비에 들어가게 된다.
이현상이 발생한 이유는 test의 맴버는 현재 2차 캐시 디비를 검색하여 현재는 1차 캐시 영역에 영속화가 되어있는 객체이다. 그 이유는 OSIV 가 작동하여 트랜젝션이 종료 되어도 영속성컨텍스트 영역이 죽지않고 계속 살아있기때문이다.
이상태에서 m.changeName 메소드를 실행하여 멤버의 이름을 바꿔 영속성컨텍스트가 더티체킹 에의해 변경된 엔티티값을 쓰기지연 영역에 DB에 넘겨줄 SQL 문이 저장된다.
otherBusiness 로직에서 메소드 종료시 커밋할때 영속성컨텍스트에 저장되어있는 SQL을 flush 한후 커밋을해버린다.
이는 서비스 로직이 비대해지면 원하지않는 데이터가 언제든이 커밋되어 장애를 일이클수 있는 상황이 발생한다는 의미이다.