스프링 프로젝트를 하면서 @Transactional이라는 애노테이션을 자주 사용한다.
하지만 정확하게 어떻게 사용하는지 모르기에 정리를 시작한다..😶😶
Transaction은 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위이다.
ACID(원자성, 일관성, 고립성, 지속성)는 데이터베이스 트랜잭션이 안전하게 수행하는 것을 보장하기 위한 성질이다.
- 원자성(Atomicity)
- 한 트랜잭션 내에서 실행하는 작업들은 모두 성공하거나 모두 실패해야한다.
- 일관성(Consistency)
- 트랜잭션이 실행을 성공했을 때 이전의 상태와 결과의 상태가 항상 일관된 상태로 있어야한다.
- 격리성(Isolation)
- 동시에 실행되는 트랜잭션들이
서로 영향을 미치지 않도록
격리- 영속성(Durability)
- 성공적으로 수행된 트랜잭션은 영원히 반영되어야 한다는 성질
public class UserService {
@Transactional
public Long registerUser(User user) {
// execute some SQL that e.g.
// inserts the user into the db and retrieves the autogenerated id
// userDao.save(user);
return id;
}
}
@Transactional을 사용하기 위해서는 Spring AOP의 동작과정, 프록시 생성, 주의사항(rivate/protected 메서드는 @Transaction을 무시한다.)을 알아야 하는데 이는 링크에 너무 잘 정리되어 있어 읽어보고 넘어가자
isolaion
propagation
noRollbackFor
rollbackFor
timeout
readOnly
트랜잭션 문제상황
- Dirty read: 동시 트랜잭션의 커밋되지 않은 변경 내용을 조회하는 상황 (데이터 불일치)
- Nonrepeatable read: 동시 트랜잭션이 동일한 행을 업데이트하고 커밋하는 경우, 행을 다시 조회할 때 다른 값을 얻 는 상황
- Phantom read: 다른 트랜잭션이 특정 범위의 행을 추가/제거할 경우, 커밋 전/후 조회 결과가 다른 상황
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void example(String message) {
// ...
}
격리 레벨 설정
- DEFAULT
- READ_UNCOMMITTED (level 0)
- READ_COMMITTED (level 1)
- REPEATABLE_READ (level 2)
- SERIALIZABLE (level 3)
트랜잭션 동작 도중 다른 트랜잭션을 호출하는 상황에서 선택할 수 있는 옵션
@Transactional(propagation = Propagation.REQUIRED)
public void example(String user) {
// ...
}
전파 전략 설정
- REQUIRED (default)
- SUPPORTS
- MANDATORY
- NEVER
- NOT_SUPPORTED
- REQUIRES_NEW
- NESTED
선언적 트랜잭션에서 런타임 예외가 발생하면 롤백 수행
특정 상황에서 강제로 롤백하거나 런타임 예외에서 롤백 제외
@Transactional(rollbackFor=Exception.class)
@Transactional(noRollbackFor=Exception.class)
지정한 시간 내에 해당 메서드 수행이 완료되지 않은 경우 rollback(단위 : second)
@Transactional(timeout=10)
@Transactional(readOnly = true)