Spring Boot @Transactional 어노테이션을 이해하기 위해 @Transactional 어노테이션이란 무엇입니까? 제공하는 설정은 무엇입니까?
1편에 이어 2편에서는 @Transactional 어노테이션이 제공해 주는 트랜잭션 롤백(Transaction Rollback) 규칙과 시간제한(Transaction Timeout), readOnly Flag와 JPA에서의 ReadOnly Flag에 특징에 대해 계속 살펴보겠습니다.
1편을 아직 보지 않은 분은 아래의 링크를 참조해 주셔서 감사합니다.
https://colevelup./34
다음 예제에서는 user entity와 user repository가 간단하다고 가정합니다.
타임아웃
모든 트랜잭션에 대해 @Transactinal 어노테이션을 사용하여 트랜잭션 시간 초과를 제공할 수 있습니다.
트랜잭션 시간 초과(timeout=10)를 정의하면 트랜잭션이 미리 정해진 시간 내에 완료되어야 합니다.
그렇지 않으면 트랜잭션 롤백시키다 트랜잭션 예외(트랜잭션 시간 만료 오류)가 발생했습니다.
라고 말합니다.
시간 값의 유형은 정수여야 하며 밀리초 단위로 간주됩니다.
timeout 설정 값의 default는 -1입니다.
즉 default에서는 timeout이 지원되지 않습니다.
@Service
public class UserServiceTimeOut {
@Autowired
private UserRepository userRepository;
@Transactional(timeout = 10)
public void myTransactionalMethod() {
// Do some database operations that might take some time
userRepository.findAll();
userRepository.save(new User());
// ...
}
}
readOnly Flag
readOnlyFlag를 사용하면 트랜잭션을 읽기 전용으로 설정할 수 있습니다.
baldung은 실제로 읽기 전용 플래그가 설정된 경우 삽입 또는 업데이트가 발생하지 않는다고 확신할 수 없으며 이 동작은 데이터베이스 공급업체에 따라 다릅니다.
또한 트랜잭션 컨텍스트 외부에서 작업이 발생하면 플래그는 무시됩니다.
@Service
public class UserServiceReadOnly {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = true)
public List<User> getUsers() {
return StreamSupport.stream(userRepository.findAll().spliterator(), false)
.collect(Collectors.toList());
}
}
JPA에서 readOnly = true
@Transactional에 readOnly = true 옵션을 주면 Spring Framework가 세션 플래시 모드를 MANUAL로 설정그리고 강제로 플래시를 호출하지 않는 한 플래시가 발생하지 않으며 트랜잭션이 커밋되어 실수로 엔티티가 등록, 변경 및 삭제되는 것을 방지합니다.
수 있습니다.
readOnly=true 설정의 이점
오류로 인한 수정 방지
트랜잭션이 읽기 전용으로 표시된 경우 해당 트랜잭션 내에서 엔터티를 변경하려고 하면 예외가 발생합니다.
이렇게 하면 실수로 엔터티를 변경할 수 없으며 데이터 일관성을 유지할 수 있습니다.
성능 향상
트랜잭션이 읽기 전용으로 표시되면 JPA는 엔티티의 스냅샷을 저장하거나 변경사항을 감지할 필요가 없습니다.
그러므로 특히 많은 엔티티에 액세스하지만 변경되는 엔티티는 거의없는 상황에서 상당한 성능 향상가져올 수 있습니다.
readOnly = true 설정 제한
읽기 전용 트랜잭션 제한
트랜잭션이 읽기 전용인 경우, 지속성 컨텍스트 내에서 엔터티를 관리할 수 없습니다.
즉, 기본 캐시 또는 지연 로드와 같은 기능을 사용할 수 없습니다.
.
엔터티에서 지연 로드된 속성에 액세스하려고 하면 예외가 발생합니다.
읽기 전용 트랜잭션이 모든 상황에 적합하지는 않습니다.
트랜잭션 내에서 데이터를 변경해야 하는 경우 읽기 전용 트랜잭션을 사용하지 마십시오.
또한 특정 상황에서는 읽기 전용 트랜잭션이 상당한 이점을 제공한다는 것을 측정하고 검증하지 않는 한 성능을 최적화하기 위해 읽기 전용 트랜잭션을 사용하지 마십시오.
지속성 컨텍스트와 캐시에 대해 혼란스러울 경우 이전 게시물을 참조해 주셔서 감사합니다.
https://colevelup./21
(JPA) Persistence context(지속성 컨텍스트) 및 EntityManager
JPA와 ORM의 간결한 정의와 JPA의 중요한 영속 컨텍스트(Persistence Context)와 엔티티 관리자(Entity Manager), 영속 컨텍스트 유형(Persistence Context type), 영속 컨텍스트(Persistence Context)의 장점
colevelup.
https://colevelup./22
(JPA) 엔티티 수명 주기, 기본 캐시, 변경 감지(Dirty-Checking)
JPA의 엔티티 수명 주기와 1차 캐시(First-Level-Cache) 및 1차 캐시의 장점, 변경 감지(Dirty-Checking) 및 플래시(Flush())가 내부적으로 어떻게 작동하는지 알아보기 합시다.
colevelup.
트랜잭션 롤백(Rollback Rules)
roolbackFor 및 noRollbackFor annotation Parameter를 사용하여 트랜잭션 롤백을 수행할지 여부에 대한 설정을 지정할 수 있습니다.
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(rollbackFor = { SQLException.class })
public void updateUser(User user) throws SQLException {
userRepository.save(user);
}
@Transactional(noRollbackFor = { NullPointerException.class })
public User getUserById(Long id) throws NullPointerException {
return userRepository.findById(id)
.orElseThrow(() -> new NullPointerException("User not found"));
}
}
클래스 수준에서 @Transactional을 사용하여 UserService 클래스의 모든 메서드가 트랜잭션 내에서 실행되도록 지정
updateUser() 메서드가 메서드 실행 중 SQLException이 발생했을 때 트랜잭션을 롤백하도록 지정
getUserById() 메소드에도 @Transactional 어노테이션이 지정되어 있으며,
NullPointerException 때문에 트랜잭션이 롤백되지 않도록 지정
Try Catch로 exception을 Catch하면?
트랜잭션 메소드가 실행되면 Spring Boot는 메소드를 트랜잭션에 래핑합니다.
메서드를 실행하는 동안 예외가 발생하면 Spring Boot는 기본적으로 트랜잭션을 롤백합니다.
예외가 try-catch 블록 내에서 포착되어 처리되는 경우에도 트랜잭션 관리자는 트랜잭션을 롤백합니다.
트랜잭션 메소드의 실행중에 발생하는 uncheckedException (즉, RuntimeException 와 그 서브 클래스) 또는 error 는, default 로서 롤백의 타겟이라고 보여집니다.
트랜잭션 관리자가 트랜잭션을 롤백하지 않게하려면 위에서 사용했습니다.
noRollbackFor 속성을 사용하여 롤백을 트리거해서는 안되는 예외를 지정하여 롤백을 수행하지 않을 수 있습니다.
예
@Transactional(noRollbackFor = { CustomException.class })
public void myTransactionalMethod() throws CustomException {
try {
// code that may throw CustomException
} catch (CustomException e) {
// exception handling code
}
}
위와 같이, updateUser() 메소드와 getUserById() 메소드의 메소드간에 트랜잭션(transaction) 동작을 다르게 지정할 수 있어 클래스내 개개의 메소드의 트랜잭션(transaction) 동작을 보다 세세하게 제어할 수 있습니다.
참고
https://www.baeldung.com/transaction-configuration-with-jpa-and-spring
https://dzone.com/articles/how-does-spring-transactional