들어가기에 앞서
스프링 Todo List 프로젝트 중 JPA의 Dirty Checking 기능이 작동하지 않아 이유에 대해 함께 프로젝트를 진행 중이던 팀원에게 물어보니, @Transactional을 Update Service에 붙이지 않아서 Dirty Check가 이루어지지 않았다는 사실을 알려주었다.
단순히 @Transactional은 오류 발생 시 롤백을 위함으로 알고 있던 나에게는 충격으로 다가왔다.
그렇기에 @Transactional 어노테이션에 대해 제대로 정리를 해야겠다는 생각을 하게 되었다.
@Transactional과 영속성 컨텍스트에 대해 알아보기 전에 먼저 JPA의 Dirty Checking 기능에 대해 알아보겠다.
JPA Dirty Checking
JPA는 Entity Manager를 통해 Entity의 저장/조회/수정/삭제를 실행한다.
Entity Manager의 메서드를 확인해보면 막상 수정에 해당하는 메서드는 존재하지 않는다.
대신에 Entitiy Manager는 수정에 해당하는 더티 체킹(Dirty Checking)을 지원한다.
영속성 컨텍스트에 속하는 Entity의 변경사항이 발생할 때도 변경 데이터들을 저장해주는데 이것이 바로 Dirty Checking이다.
Dirty Checking은 아래 두 조건을 만족하는 경우에만 이뤄진다.
- 영속 상태(Managed) 안에 있는 엔티티인 경우
- Transaction 안에서 엔티티를 변경하는 경우
그럼 이제 영속성 컨텍스트에 대해 알아보자.
영속성 컨텍스트
영속성 컨텐스트란 Entity를 영구 저장하는 환경이라는 뜻이다. 애플리케이션과 DB 사이에서 Entity를 보관하는 가상의 캐시와 같은 역할을 한다. Entity Manager가 Entity를 저장하거나 조회하면 Entity Manager는 영속성 컨텍스트에 Entity를 보관하고 관리한다.
em.persist(todo);
위 코드는 Entity Manager를 사용해 todo Entity를 영속성 컨텍스트에 저장한다는 의미이다.
영속성 컨텍스트는 Entity Manager를 생성할 때 하나 만들어지고, Entity Manager를 통해서 영속성 컨텍스트에 접근하고 관리할 수 있다.
위 그림을 통해 Entity와 영속성 컨텍스트 간의 관계를 알 수 있다.
비영속 : 생성한 객체가 아직 영속성 컨텍스트에 저장되지 않았을 때이다. (new/transient)
TodoEntity todo = new TodoEntity();
영속 : 엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장한 상태를 말하며 영속성 컨텍스트에 의해 관리된다는 뜻이다.
em.persist(todo);
준영속 : 영속성 컨텍스트가 관리하던 영속 상태의 엔티티 더이상 관리하지 않으면 준영속 상태가 된다. 특정 엔티티를 준영속 상태로 만드려면 em.datach()를 호출하면 된다.
// 엔티티를 영속성 컨텍스트에서 분리해 준영속 상태로 만든다.
em.detach(todo);
// 영속성 콘텍스트를 비워도 관리되던 엔티티는 준영속 상태가 된다.
em.claer();
// 영속성 콘텍스트를 종료해도 관리되던 엔티티는 준영속 상태가 된다.
em.close();
삭제 : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.
em.remove(todo);
영속성 컨텍스트가 Entity를 관리하면 다음과 같은 장점이 있다.
- 1차 캐시
- 동일성 보장
- 트랙잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
플러시 : 영속성 컨텍스트의 변경 내용을 DB에 반영한다. 영속성 컨텍스트의 엔티티를 지우는게 아니라 변경 내용을 데이터베이스에 동기화하는 것이다. 다음과 같은 경우에 플러시가 일어난다.
- em.flush() 실행 시
- Transaction Commit
- JPQL 쿼리 실행 시
이제 @Transactional 어노테이션에 대해 알아보겠다.
@Transactional 어노테이션
Transaction은 DB의 상태를 변경하는 작업 또는 한번에 수행되어야 하는 연산들을 의미한다.
이 Transaction을 사용하기 위해서 클래스나 메서드에 @Transactional 어노테이션을 붙여주면 된다.
그렇게 되면 해당 범위는 Transation이 보장되게 되고, 영속성 컨텍스트가 생성된다.
Transaction이 보장되게 되면 연산 수행 중 오류가 발생하게 되면 자동적으로 롤백을 해준다.
그렇기 때문에 @Transactional 어노테이션은 Create, Update, Delete처럼 DB내의 데이터를 조작해야하는 경우에 오류를 대비하여 사용되어야 한다.
다만 @Transactional을 사용할 때에 아래 두 사항을 주의해야 한다.
- 같은 Transation 내에서 여러 Entity Manager를 쓰더라도, 이는 같은 영속성 컨텍스트를 사용한다.
- 같은 Entity Manager를 쓰더라도 Transation이 다르면 다른 영속성 컨텍스트를 사용한다.
참고
https://interconnection.tistory.com/121
JPA 더티 체킹(Dirty Checking)이란?
JPA(Java Persistence API)를 사용하면서 더티 체킹과 트랜잭션의 관계에 대해서 알고 있지 않으면, 비즈니스 로직에서 다루는 엔티티 데이터가 꼬이는 경우가 발생합니다. 데이터가 꼬이는 경우를 방
interconnection.tistory.com
JPA 영속성 컨텍스트란?
영속성 컨텐스트란 엔티티를 영구 저장하는 환경이라는 뜻이다. 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.em.persist
velog.io
https://kafcamus.tistory.com/30
@Transactional 어노테이션의 이해
나는 보통 서비스 코드에 @Transactional 어노테이션을 활용해준다. 그런데 사실 뜻도 잘 모르고 좋다고 그래서 쓴거라...지나고 보니 정확히 설명하기가 어려웠다. 그런고로, 해당 어노테이션의 작
kafcamus.tistory.com
'개발 > 스프링 개념' 카테고리의 다른 글
[Spring] Session이란? (0) | 2023.01.25 |
---|---|
[Spring] Select에 @Transaction을 사용하는 이유 (0) | 2023.01.20 |
[Spring] Spring 웹 계층 구조 (0) | 2023.01.20 |
[Spring] 의존성 주입이란? (0) | 2023.01.13 |
[Spring] Open-In-View란? (0) | 2022.11.19 |