@Transactional
트랜젝션의 4가지 특징
ACID
transaction은 ACID의 특성을 가집니다.
원자성(Atomicity)
트랜잭션과 관련된 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장하는 특성
일관성(Consistency)
트랜잭션이 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지하는 특성
독립성(Isolation)
트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 특성
지속성(Durability)
성공적으로 수행된 트랜잭션은 영원히 반영되어야 함을 의미하는 특징
스템 문제, DB 일관성 체크 등을 하더라도 유지되어야 함을 의미합니다.
@Transactional Annotation
@Service
@Transactional
public class FooService {
//...
}
어노테이션에서 할 수 있는 설정
- Propagation Type
- Isolation Level
- Timeout
- readOnly
- Rollback
주의할점: 롤백은 unchecked exception에서만 발생한다. checked exception일 경우 롤백되지 않으니 주의해야한다. 주로 서비스 레이어에서 사용된다. 여러 DAO 메서드를 호출해 하나의 트랜잭션으로 묶기 때문이다.
스프링에서 @Transactional 이용한 트랜젝션 처리
- 방법: 메서드나 클래스에 어노테이션을 달아주기
- 클래스, 메서드 둘다 달 경우 메서드 레벨의
@Transactional이 우선적으로 적용된다.
테스트 환경에서 @Transactional 동작
테스트 메서드에 @Transactional을 달 경우, 메서드가 종료될 때 자동으로 롤백된다.
TestTransaction
TestTransaction 클래스는 @Transactional 이 적용된 테스트 메서드를 감싸고 있는 트랜잭션과 상호 작용할 수 있는 기능을 가지는 유틸리티 클래스
@Transactional(readOnly=true)
@Transactional 작업을 처리하기 위해서는 많은 리소스 사용
CUD 작업을 할 경우 이전 상태로 돌리기 위해서는 이전 상태에 대한 정보가 있어야함
하지만, Read 연산의 경우 이전 상태 변화가 없기 때문에 lock을 적용할 필요가 없음
그렇기 때문에, readOnly=true로 메서드가 읽기 전용인 것을 명시하는 것과, 영속성 컨텍스트에 관리 받지 않게 됨
변경감지 수행을 하지 않아 낮은 격리 수준 사용
예상 문제들
Proxies
스프링은 모든 @Transactional 어노테이션에 대해 프록시를 생서한다.
명심해야 할 중요한 점은 트랜잭션 빈이 인터페이스를 구현하는 경우 기본적으로 프록시는 Java 동적 프록시가 된다는 것이다.
즉, 프록시를 통해 들어오는 외부 메서드 호출만 가로채게 된다.자체 호출 호출은 메서드에 @Transactional 어노테이션이 있더라도 트랜잭션을 시작하지 않는다.
프록시를 사용할 때 주의해야 할 또 다른 사항은 public 메서드에만 @Transactional 어노테이션을 추가해야 한다는 것이다.
Read-only
사실 읽기 전용 플래그가 설정된 경우 삽입 또는 업데이트가 발생하지 않는다고 확신할 수 없다. 이 동작은 공급업체에 따라 달라지지만, JPA는 공급업체에 구애받지 않는다.
또한 읽기 전용 플래그는 트랜잭션 내부에서만 관련된다는 점을 이해하는 것이 중요하다. 트랜잭션 컨텍스트 외부에서 작업이 발생하면 플래그가 무시된다.
ID는 롤백되지 않는다.
Auto Increment 옵션으로 id를 지정하는데, 이때 증가된 id는 트랜잭션에 롤백되어도 감소하지 않는다.
Auto Increment 작업이 Transaction 범위 밖에서 동작하기 때문이다.
왜 그럴까? 동시성 문제 때문이다. 여러 요인으로 트랜잭션이 실패할 수 도 있는데, 트랜잭션이 다른 사람 회원가입 성공 여부를 기다릴 수는 없기 때문이다.