일단 @Transactional 을 사용하기 전 트랜잭션에 대해 알아야 한다 트랜잭션에 대해 한번 알아보자.
👉트랜잭션(transaction) 정의
- 트랜잭션(transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미한다.
👉트랜잭션 특징
- 트랜잭션은 데이터베이스 시스템에서 병행 제어 및 회복 작업 시 처리되는 작업의 논리적 단위이다.
- 사용자가 시스템에 대한 서비스 요청시 시스템이 응답하기 위한 상태 변환 과정의 작업단위이다.
- 하나의 트랜잭션은 Commit되거나 Rollback된다.
👉트랜잭션(transaction) 성질
- 원자성 (Atomicity)
- 한 트랜잭션 내에서 실행한 작업들은 하나로 본다. 모두 성공하거나 모두 실패
- 일관성 (Consistency)
- 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다.
- 격리성 (lsolation)
- 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야 한다.
- 영속성,지속성 (Durability)
- 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.
👉트랜잭션(transaction) 연산 및 상태
- Commit연산
- Commit연산은 한개의 논리적 단위에 대한 작업이 성공적으로 끝났고 데이터베이스가 다시 일관된 상태에 있을 때, 이 트랜잭션이 행한 갱신 연산이 완료된 것을 트랜잭션 관리자 에게 알려주는 연산이다.
- Rollback연산
- Rollback연산은 하나의 트랜잭션 처리가 비정상적으로 종료되어 데이터베이스의 일관성을 깨트렸을 때, 이 트랜잭션의 일부가 정상적으로 처리되었더라도 트랜잭션의 원자성을 구현하기 위해 이 트랜잭션이 행한 모든 연산을 취소하는 연산이다.
- Rollback시에는 해당 트랜잭션을 재시작하거나 폐기한다.
이제 스프링에서 트랜잭션 처리를 지원하는데 그중 어노테이션 방식으로 @Transactional을 선언하여 사용하는 방법을 알아보자.
이런식으로 클래스나 메서드 위에 @Transactional이 추가되면 ,이 클래스나 메서드에 트랜잭션 기능이 적용된 프록시 객체가 생성된다.
이 프록시 객체는 @Transactional이 포함된 메서드가 호출 될 경우, PlatformTransactionManager를 사용하여 트랜잭션을 시작하고 ,정상여부에 따라 Commit 또는 Rollback한다.
적용방식은 위 사진처럼 하면 된다.
이제 다수의 트랜잭션이 경쟁시 발생할 수 있는 문제를 알아보자
- Dirty read
- 트랜잭션1 이 어떠한 값을 A에서 B로 변경하고 아직 커밋하지 않은 상황에서 트랜잭션2가 같은 값을 읽는 경우 트랜잭션2는 값을 조회하면 B가 조회된다.(만약 트랜잭션1이 롤백을 하게되면 트랜잭션2는 잘못된 값을 읽은 것이다.)
- 위 같은 상황을 트랜잭션이 완료되지 않은 상황에서 데이터에 접근을 허용할 경우 발생할 수 있는 데이터 불일치 이다.
- Non-Repeatable Read
- 트랜잭션1이 A라는 값을 읽고, 이후 A는 같은 쿼리를 실행할 예정인데, 그 사이에 트랜잭션 2가 값을 B로 바꾸고 커밋해버리면 트랜잭션1이 같은 쿼리를 두번 날리는 사이 두 쿼리의 값은 달라진다.
- 한 트랜잭션에서 같은 쿼리를 투번 실행했을 경우 발생할 수 있는 데이터 불일치이다.
위와 같은 문제들을 해결할 수 있는 속성에 대해서 알아보자.
@Transactional속성
1.lsolation(격리 수준)
- DEFAULT
- 기본 격리 수준
- READ_COMMITED
- 트랜잭션이 커밋 된 확정 데이터만 읽기 허용(Dirty read 방지)
- REPEATABLE_READ
- 트랜잭션이 완료될 때까지 SELECT문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능하다.(Non-Repeatable read 방지)
- 행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제가 불가능 하기때문에 같은 데이터를 두 번 쿼리했을 때 일관성 있는 결과를 리턴한다.
- SERIALIZABLE
- 트랜잭션이 완료될 때까지 SELECT문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능하다
2.readOnly(읽기 전용)
- 트랜잭션을 읽기 전용으로 설정할 수 있다.
- 성능을 최적화하기 위해 사용할 수도 있고 특정 트랜잭션 작업 안에서 쓰기 작업이 일어나는 것을 의도적으로 방지하기 위해 사용할 수도 있다.
- 읽기 전용 트랜잭션이 시작된 이후 INSERT, UPDATE, DELETE 같은 쓰기 작업이 진행되면 예외가 발생한다.
- ex: @Transactional(readOnly = true)
3. 트랜잭션 롤백 예외(rollback-for, rollbackFor, rollbackForClassName)
- 선언적 트랜잭션에서는 런타임 예외가 발생하면 롤백한다.
- 예외가 전혀 발생하지 않거나 체크 예외가 발생하면 커밋한다. 체크 예외를 커밋 대상으로 삼은 이유는 체크 예외가 예외적인 상황에서 사용되기보다는 리턴 값을 대신해서 비즈니스적인 의미를 담은 결과를 돌려주는 용도로 많이 사용되기 때문이다.
- 스프링에서는 데이터 엑세스 기술의 예외는 런타임으로 전환돼서 던져지므로 런타임 예외만 롤백 대상으로 삼은것이다.
- rollbackFor 속성설정
- 예: @Transactional(rollbackFor=Exception.class)
- 특정 예외가 발생 시 강제로 Rollback
- noRollbackFor 속성설정
- 예: @Transactional(noRollbackFor=Exception.class)
- 특정 예외의 발생 시 Rollback 처리되지 않음
4.전파 옵션 (propagation)
- 트랜잭션 동작 도중 다른 트랜잭션을 호출(실행)하는 상황이에 선택할 수 있는 옵션이다.
- @Transactional의 propagation 속성을 통해 피호출 트랜잭션의 입장에서는 호출한 쪽의 트랜잭션을 그대로 사용할 수도 있고, 새롭게 트랜잭션을 생성할 수도 있다
- REQUIRED
- 디폴트 속성, 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 새로운 트랜잭션을 생성한다.
- SUPPORTS
- 이미 시작된 트랜잭션이 있으면 참여하고 그렇지 않으면 트랜잭션 없이 진행하게 만든다.
- REQUIRES_NEW
- 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성
- MANDATORY
- REQUIRED와 비슷하게 이미 시작된 트랜잭션이 있으면 참여한다.
- 반면에 트랜잭션이 시작된 것이 없으면 새로 시작하는 대신 예외를 발생시킨다.
- 혼자서는 독립적으로 트랜잭션을 진행하면 안 되는 경우에 사용한다.
- REQUIRES_NEW
- 항상 새로운 트랜잭션을 시작한다.
- 이미 진행 중인 트랜잭션이 있으면 트랜잭션을 잠시 보류시킨다.
- NOT_SUPPORTED
- 트랜잭션을 사용하지 않게 한다.
- 이미 진행 중인 트랜잭션이 있으면 보류시킨다.
- NEVER
- 트랜잭션을 사용하지 않도록 강제한다.
- 이미 진행 중인 트랜잭션도 존재하면 안된다 있다면 예외를 발생시킨다.
- NESTED
- 이미 진행중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다.
- 중첩 트랜잭션은 트랜잭션 안에 다시 트랜잭션을 만드는 것이다.
5.timeout속성
- 지정한 시간 내에 해당 메소드 수행이 완료되이 않은 경우 rollback 수행. -1일 경우 no timeout(Default=-1)
- ex) @Transactional(timeout=10)
'Dev > Spring' 카테고리의 다른 글
[Spring] AOP(Aspect Oriented Programming) (0) | 2021.09.10 |
---|---|
ResponseEntity (0) | 2021.08.25 |
Spring REST Docs (0) | 2021.08.23 |
DAO,DTO,Entity Class (0) | 2021.08.13 |
@RequestMapping에 대하여 (0) | 2021.07.24 |