JPA 영속성 컨텍스트
더티 체킹이 일어나는 환경은 아래 두 가지 조건이 충족되어야 한다.
Transaction은 두 가지 방식
으로 사용할 수 있다.
여기서 위 1번/2번 Transaction 사용 예를 보이겠습니다.
1번과 2번은 PK를 id로 가지고 있는 User의 name을 바꾸는 동일한 작업을 하겠습니다.
@Service
public class ExampleService {
@Transactional
public void updateInfo(Long id, String name) {
User user = userRepository.findById(id);
user.setName(name);
}
}
@Service
public class ExampleService {
public void updateInfo(Long id, String name) {
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
// 1. 트랜잭션 시작
tx.begin();
// 2.User 엔티티를 조회 & User 스냅샷 생성
User user = em.find(User.class, id);
// 3.User 엔티티의 name을 변경
user.setName(name);
// 4. 트랜잭션
// 5.User 스냅샷과 최종 user의 내용을 비교해서 Dirty를 Checking 해서 Update Query 발생
tx.commit();
}
}
더티 체킹이 발생하면 어떤 일이 일어날까?
위 1번/2번에서 더티 체킹이 일어나면 다음과 같은 Query 문이 발생한 것을 볼 수 있다.
분명 user의 업데이트에 대한 메서드를 호출하지 않았음에도 불구하고 Query가 발생시킨다.(더티 체킹
)
그리고 트랜잭션 커밋 이후, 트랜잭션이 끝나는 시점에 모든 엔티티에 대한 정보를 DB에 반영한다.
더티 체킹시, 발생하는 Query
Hibernate:
update
**user
set**
name=?
**where**
id=?
그럼 트랜잭션이 아닌 상태에서 엔티티 내용이 변경되면 어떻게 될까?
Service Layer 안, 동일한 코드 메서드에 @Transactional을 사용한 경우와 사용하지 않은 경우를 예시로 들겠습니다.
public void updateInfo() {
User user = userRepository.findById(2L)
.orElseThrow(() -> new ErrorCodeException(ErrorType.USER_IS_NOT_EXISTING));
user.setEmail("hello@gmail.com");
System.out.println(userRepository.existsByEmail("hello@gmail.com"));
}
@Transactional을 사용한 경우
- Table: User에서 PK id가 2인 user 엔티티 객체 조회
- user의 email을 수정(Dirty Checking 발생)
- hello@gmail.com을 email로 가진 user 엔티티 유무 확인, 2번 과정에서 수정되었기에 true가 출력됨
@Transactional을 사용하지 않은 경우
- Table: User에서 PK id가 2인 엔티티 객체 조회
- user의 email을 수정
- hello@gmail.com을 email로 가진 user 엔티티 유무 확인
4. 2번 과정에서 수정되지 못하여 false 출력
Transaction을 사용하지 않아서 반영되지 못한 내용을 반영하고 싶은 경우, 원하는 시점에 save 혹은 saveAndFlush를 사용하면 된다.
@Transactional을 사용하지 않은 경우의 반영하는 케이스
public void updateInfo() {
User user = userRepository.findById(2L)
.orElseThrow(() -> new ErrorCodeException(ErrorType.USER_IS_NOT_EXISTING));
user.setEmail("hello@gmail.com");
userRepository.saveAndFlush(user);
System.out.println(userRepository.existsByEmail("hello@gmail.com"));
}
1. Table: User에서 PK id가 2인 user 엔티티 객체 조회
2. user의 email을 hello@gmail.com로 수정
3. hello@gmail.com를 email로 가진 user 엔티티 유무 확인,
이번엔 userRepository.saveAndFlush(user);를 통해서 반영이 되어 true 출력
JPA 영속성 컨텍스트
더티 체킹이 일어나는 환경은 아래 두 가지 조건이 충족되어야 한다.
Transaction은 두 가지 방식
으로 사용할 수 있다.
여기서 위 1번/2번 Transaction 사용 예를 보이겠습니다.
1번과 2번은 PK를 id로 가지고 있는 User의 name을 바꾸는 동일한 작업을 하겠습니다.
@Service
public class ExampleService {
@Transactional
public void updateInfo(Long id, String name) {
User user = userRepository.findById(id);
user.setName(name);
}
}
@Service
public class ExampleService {
public void updateInfo(Long id, String name) {
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
// 1. 트랜잭션 시작
tx.begin();
// 2.User 엔티티를 조회 & User 스냅샷 생성
User user = em.find(User.class, id);
// 3.User 엔티티의 name을 변경
user.setName(name);
// 4. 트랜잭션
// 5.User 스냅샷과 최종 user의 내용을 비교해서 Dirty를 Checking 해서 Update Query 발생
tx.commit();
}
}
더티 체킹이 발생하면 어떤 일이 일어날까?
위 1번/2번에서 더티 체킹이 일어나면 다음과 같은 Query 문이 발생한 것을 볼 수 있다.
분명 user의 업데이트에 대한 메서드를 호출하지 않았음에도 불구하고 Query가 발생시킨다.(더티 체킹
)
그리고 트랜잭션 커밋 이후, 트랜잭션이 끝나는 시점에 모든 엔티티에 대한 정보를 DB에 반영한다.
더티 체킹시, 발생하는 Query
Hibernate:
update
**user
set**
name=?
**where**
id=?
그럼 트랜잭션이 아닌 상태에서 엔티티 내용이 변경되면 어떻게 될까?
Service Layer 안, 동일한 코드 메서드에 @Transactional을 사용한 경우와 사용하지 않은 경우를 예시로 들겠습니다.
public void updateInfo() {
User user = userRepository.findById(2L)
.orElseThrow(() -> new ErrorCodeException(ErrorType.USER_IS_NOT_EXISTING));
user.setEmail("hello@gmail.com");
System.out.println(userRepository.existsByEmail("hello@gmail.com"));
}
@Transactional을 사용한 경우
- Table: User에서 PK id가 2인 user 엔티티 객체 조회
- user의 email을 수정(Dirty Checking 발생)
- hello@gmail.com을 email로 가진 user 엔티티 유무 확인, 2번 과정에서 수정되었기에 true가 출력됨
@Transactional을 사용하지 않은 경우
- Table: User에서 PK id가 2인 엔티티 객체 조회
- user의 email을 수정
- hello@gmail.com을 email로 가진 user 엔티티 유무 확인
4. 2번 과정에서 수정되지 못하여 false 출력
Transaction을 사용하지 않아서 반영되지 못한 내용을 반영하고 싶은 경우, 원하는 시점에 save 혹은 saveAndFlush를 사용하면 된다.
@Transactional을 사용하지 않은 경우의 반영하는 케이스
public void updateInfo() {
User user = userRepository.findById(2L)
.orElseThrow(() -> new ErrorCodeException(ErrorType.USER_IS_NOT_EXISTING));
user.setEmail("hello@gmail.com");
userRepository.saveAndFlush(user);
System.out.println(userRepository.existsByEmail("hello@gmail.com"));
}
1. Table: User에서 PK id가 2인 user 엔티티 객체 조회
2. user의 email을 hello@gmail.com로 수정
3. hello@gmail.com를 email로 가진 user 엔티티 유무 확인,
이번엔 userRepository.saveAndFlush(user);를 통해서 반영이 되어 true 출력
더티 체킹 (Dirty Checking)이란?
[Spring JPA] Dirty Checking(더티체킹)이란?
[Spring Data JPA] 더티 체킹(Dirty Checking)