여러개의 작업을 하나로 묶은 것
롤백 = 묶은 작업 중 하나라도 잘못되면, 작업이 실행되기 이전의 상태로 돌립니다.
데이터베이스를 수정하는 작업에서는 반드시 사용해야 합니다.
b) 왜냐하면 데이터 베이스를 수정하다가 오류가 나면 데이터 베이스에 잘 못된 데이터가 들어갈 수 있습니다. 이 때 롤백기능을 사용해서 잘못된 데이터가 추가되지 않도록 만들어야 합니다.
한번에 이루어져야 하는 작업들을 관리할 때 사용합니다.
예시
@Transactional
public void Service(){
minusPoint();
sendPoint();
plusPoint();
}
위 작업에서 포인트를 주고받습니다. 만약 포인트를 다른 사람엑 전송하기 위해 minuPoint()를 실행한 후 오류가 난다면, 포인트는 전송되지 않고 사라집니다.
따라서 포인트를 주고 받는 행위에 포함되는 모든 작업을 트랜잭션으로 묶어서 작업 도중에 오류가 난다면 롤백이 일어날 수 있도록 해야합니다.
@Transactional
을 선언하여 사용하는 방법이 일반적이며, 이 방식으로 생성된 트랜잭션을 선언적 트랜잭션이라고 부릅니다.클래스, 메서드 코드 위에 @Transactional
어노테이션이 추가되면 해당 클래스에 프록시 기능이 적용된 프록시 객체가 생성됩니다.
이 프록시 객체는 @Transacitonal
이 포함된 메서드가 호출되었을 때, PlatformTransactionalManager
를 사용하여 트랜잭션을 시작하고, 정상 여부에 따라서 Commit 또는 Rollback을 합니다.
READ_UNCOMMITED (level 0) = 커밋되지 않은(트랜잭션이 처리중인) 데이터에 대해서 읽기 허용 - Dirty Read 발생 가능
READ_COMMITED ( level 1) = 트랜잭션이 커밋한 확정 데이터만 읽기 허용 - Dirty Read 발생하지 않습니다.
REPEATABLE_READ( level 2) = 트랜잭션이 완료될 때까지 해당 트랜잭션의 SELECT 문장에서 사용하는 모든 데이터에 shared lock 이 걸리기 때문에, 다른 사용자는 해당 데이터에 대한 수정이 불가능합니다.
- 한 트랜잭션이 읽은 데이터는 다른 트랜잭션이 수정, 삭제가 불가능하기 때문에 같은 쿼리를 두번 하더라도 똑같은 결과를 얻을 수 있습니다.
- Non-Repeatable Read 발생하지 않습니다.
2. propagation (전파 옵션)
- 한 트랜잭션에서 다른 트랜잭션을 호출하는 상황에서 선택할 수 있는 옵션
1. REQUIRED = 디폴트
- 부모 트랜잭션 내에서 실행하며, 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 생성합니다.
2. SUPPORTS
- 이미 시작된 트랜잭션이 있으면 참여하고 그렇지 않으면 트랜잭션없이 진행되게 합니다.
3. REQUIRES_NEW
- 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성됩니다.
- 이미 진행중인 트랜잭션이 있으면, 트랜잭션 생성을 잠시 보류시킵니다.
4. MANDATORY
- REQUIRED 와 비슷하게, 이미 시작된 트랜잭션이 있으면 참여합니다.
- 이미 시작된 트랜잭션이 없으면, 새로 시작하는 대신 예외를 발생시킵니다.
- 혼자서 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용합니다.
5. NOT_SUPPORTED
- 트랜잭션을 사용하지 않도록 강제합니다.
- 이미 실행중인 트랜잭션이 존재하면 예외를 보류시킨다.
6. NEVER
- 트랜잭션을 사용하지 않게 한다.
- 이미 진행 중인 트랜잭션이 있으면 예외를 발생시킨다.
6. NESTED
- 이미 진행중인 트랜잭션이 있으면, 중첩 트랜잭션을 시작합니다.
- 중첩 트랜잭션 = 트랜잭션안에 트랜잭션을 만드는 것
- 중첩 트랜잭션은 먼저 시작된 트랜잭션(부모 트랜잭션)의 커밋과 롤백에는 영향을 받지만 자신의 커밋, 롤백은 부모 트랜잭션에 영향을 주지 않습니다.
- EX. 쇼핑몰에서 주문트랜잭션에 로그를 남기는 작업이 있는 경우
- 이 로그를 남기는 작업이 실패한다고 해서 메인 작업까지 롤백되면 안됩니다.
- 하지만 주문작업이 실패했을 때는 로그를 남기지 않는 것이 맞습니다.
- 이 때 중첩 트랜잭션을 사용하면 됩니다.
3. readOnly 속성
- 트랜잭션을 읽기전용 속성으로 지정할 수 있습니다.
- 성능 최적화를 위해서 or 특정 트랜잭션 작업안에서 쓰기 작업이 일어나는 것을 막기 위해서 사용할 수 있습니다.
- 일부 트랜잭션의 경우 일기전용 속성을 무시하고 쓰기 작업을 허용할 수도 있습니다.
- readOnly 속성이 지정된 트랜잭션에서 INSERT, DELETE, UPDATE 작업과 같이 쓰기 작업이 일어나면 예외가 발생합니다.
- aop/tx 스키마로 트랜잭션 선언할 때는 이름 패턴을 이용해서 읽기 전용 속성으로 만드는 경우가 많다. 보통 get이나 find같은 이름의 메소드를 읽기 전용 메소드로 만들어서 사용하면 편합니다.
- `@Transactional`을 사용하여 트랜잭션을 만드는 경우는 일일이 읽기 전용 속성을 지정해줘야 합니다. `read-only` 속성 또는 `readOnly` 속성을 true로 지정하면 읽기 전용으로 지정됩니다.
- true인 경우에는 INSERT, UPDATE, DELETE 발생시 예외 발생하며, 디폴트는 false로 되어 있습니다.
- 예시
@Transaction(readOnly = true)
4. 트랜잭션 롤백 예외 (rollback-for, rollbackFor, rollbackForClassName)
- 선언적 트랜잭션에서는 런타임에서 예외(오류)가 발생하면 롤백합니다.
- 반면에 예외가 전여 발생하지 않거나 체크 예외가 발생하면 커밋합니다.
- 체크 예외가 커밋 대상인 이유 = 체크 예외가 예외적인 상황일 때 발생하기 보다는 리턴 값을 대신해서 비즈니스적인 의미를 담은 결과를 반환하는 용도로 사용되기 때문입니다.
- 스프링에서는 데이터 액세스 때 발생하는 예외는 런타임 예외로 발생하기 때문에, 런타임 예외가 일어났을 때에만 롤백이 일어납니다.
- 하지만 롤백이 일어나는 대상을 바꿀 수 있습니다.
ex. 체크 예외이지만 롤백이 일어나야하는 경우가 있다면, XML의 roolback-for 애트리뷰트나 어노테이션 `@rollback` 혹은 rollbackForClassName 속성을 사용해서 예외를 지정하면 됩니다.
rollback-for 애트리뷰트 나 rollbackForClassName 속성에는 예외 이름을 지정하면되고, `@rollbackFor`는 예외 대상 클래스에 넣어주면됩니다.
- `@Transaction` 어노테이션에서 `rollbackFor` 속성을 이용하여 지정하는 경우에는 클래스 이름 대신 클래스를 직접 사용해도 됩니다.
ex.
@Transactional(readOnly = true, rallbackFor = NoSuchMemberException.class) ```
@Transactional
어노테이션에서 롤백 관련 속성