Search
Duplicate

[JAVA] @Transactional 이란? 트랜잭션 성질 (1)

순서
5
날짜
2022/11/30
사람
상태
Done

트랜잭션이란?

트랜잭션(Transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미!
모든 트랜잭션이 같은 방식으로 작동하지는 않는다. 전체가 같이 성공하거나 실패하는 하나의 작업으로 묶인다는 것은 변치않지만, 세밀히 따지면 차이점이 존재한다.
트랜잭션이 끝나면 Commit 또는 RollBack 되어야 한다.

트랜잭션 성질

Atomicity(원자성)
하나의 트랜잭션이 더작게 나눌 수 없는 최소의 다윈라는 뜻이다. 트랜잭션이 모두 반영되거나, 아니면 전혀 반영되지 않아야 하는 특징을 나타낸다.
Consistency(일관성)
일관성은 트랜잭션이 완려된 결괏값이 일관적인 데이터베이스 상태를 유지하는 것을 말한다. 예를 들면, 고객 정보가 담겨있는 데이터베이스에 새로운 고객이 등록되면 그 데이터베이스를 참조하는 다른 하위 계층의 데이터베이스도 같은 고객의 세부정보를 가져와야 한다.
Isolation(독립성)
트랜잭션이 수행되고 있을 때, 다른 트랜잭션의 연산작업이 중간에 끼어들어 기존 작업에 영향을 주지 못하도록 하는 것을 말한다. 독립성이 보장된다면 계좌 이체작업을 진행하고 있는 도중에 계좌의 잔액을 죄하한다 거나 하는 작업을 동시에 수행할 수 없게 되는 것이다.
Durability(지속성)
트랜잭션을 성공한 후 데이터베이스에 반영된 것은 영원히 반영되어야 한다는 것을 의미한다.

@Transactional(선언적 트랜잭션)

Transaction Template와 달리 트랜잭션 처리를 코드에 직접적으로 수행하지 않음 설정 파일이나 어노테이션을 이용하여 트랜잭션의 범위, 롤백 규칙등을 정의
다음과 같은 2가지 방식으로 정의
<tx:advice> 태그를 이용
@Transactional 어노테이션을 이용한 트랜잭션 설정
현재 내가 하는 프로젝트는 @Transactional을 많이 사용함으로 해당사항으로 정리하도록 하겠다.

@Transactional 옵션

propagation : 전파옵션

트랜잭션 동작 도중 다른 트랜잭션을 호출(실행)하는 상황에 선택할 수 있는 옵션이다.
REQUIRED
디폴트 속성, 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 새로운 트랜잭션을 생성한다.
SUPPORTS
이미 시작된 트랜잭션이 있으면참여하고 그렇지 않으면 트랜잭션 없이 진행하게 만든다.
REQUIRES_NEW
부모 트랜잭션을 무시하고 새로운 트랜잭션이 생성
항상 새로운 ㅌ
이미 진행중인 트랜잭션이 있으면 트랜잭션을 잠시 보류시킨다.
MANDATORY
REQUIRED와 비슷하게 이미 시작된 트랜잭션이 있으면 참여한다.
트랜잭션이 시작된 것이 없으면새로 시작하는 대신 예외를 발생시킨다.
혼자서는 독립적으로 트랜잭션을 진행하면 안 되는 경우에 사용한다.
NOT_SUPPORTED
트랜잭션을 사용하지 않게한다.
이미 진행 중인 트랜잭션이 있으면 보류시킨다.
NESTED
이미 진행중인 트랜잭션이 있으면 중첩 트랜잭션을 시작한다.
중첩 트랜잭션은 트랜잭션 안에서 다시 트랜잭션을 만드는 것이다.

isolation : 격리수준

트랜잭션 격리 수준 (isolation)이란?
동시에 여러 사용자가 데이터에 접근할 때 어디까지 허용할까?를 정하는 옵션.
트랜잭션의 격리 수준과 데이터의 일관성은 비례한다. 격리수준이↓ 데이터 접근 및 수정이 자유롭지만  일관성은↓ 격리수준이↑ 데이터 접근 및 수정이 어렵고 일관성은 ↑
DEFAULT
별도로 정의하지 않으면 DB의 isolation Level을 따름
READ_UNCOMMITTED(Level 0)
트랜잭션이 처리 중인 커밋되지 않은 데이터를 다른 트랜잭션에 접근 가능, 접항성 때문에 권장되지 않는다.
Dirty Read : DB에 커밋하지 않은[존재하지 않는] 데이터를 읽는 현상
ex )
1.
userA의 트랜잭션이 권한데이터를 조회하여 최고관리자로 변경하고 아직 커밋하지 않았다.
2.
userB의 트랜잭션이 위와 동일한 권한데이터를 조회해서 최고권한 데이터를 받는다. 여기서 DirtyRead가 발생한다.
3.
userA의 트랜잭션이 익셉션이 발생되 데이터를 롤백한다. (최고관리자 —> 일반사용자로) 롤백
4.
현재 상황을 보면 실제 데이터는 일반사용자이지만 2번에서 최고관리자 권한으로 읽고 있는 문제가 발생한다.
READ_COMMITTED(Level 1)
트랜잭션은 커밋한 데이터만 읽음
Non-Repeatable read:
한 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면 두 쿼리의 결과가 상이하게 나타나는 일관성이 깨진 현상
oracle DB, SQL server에서 기본적으로 사용하는 Isolation level임
Non-Repeatable read 발생
ex)
1.
A 트래잭션에서 userA의 권한을 조회 : 기본권한
2.
B트랜잭션에서 userA의 권한을 관리자권한으로 변경하고 커밋
3.
A 트랜잭션에서 userA의 권한을 조회 : 관리자권한
REPEATABLE_READ(Level2)
트랜잭션이 완료될 때까지 SELECT 문장이 사용되는 모든 데이터에 Shared Lock이 걸리는 계층
트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장
다른 사용자는 트랜잭션 영역에 해당하는 데이터에 대한 수정 불가능
MySQL DBMS에서 기본으로 사용함
Non-Repeatable read 발생하지 않음
ex)
1.
A트랜잭션이 userA의 권한을 조회
2.
B트랜잭션이 userA의 권한을 변경하고 커밋
3.
A트랜잭션이 userA의 권한을 다시 조회 : undo 영역에 백업된 데이터를 반환.
Phantom read 발생
한 트랜잭션 안에서 일정 범위의 레코드를 두 번이상 읽었을때, 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상
트랜잭션 도중 새로운 레코드를 사입을 허용하기 때문에 나타남
Serializable(Level3)
트랜잭션이 완료될 때까지 SELECT 문장이 사용되는 모든 데이터에 Shared Lock이 걸리는 계층
가장 엄격한 격리 수준으로 완벽한 읽기 일관성 모드를 제공함
다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능

rollbackFor

기존에 트랜잭션을 작성할때 @Transactional만을 실행했다. 실무에서 이와같이 작성하였는데, 피드백을 받았다. ‘익셥션이 터질때 과연 롤백이 제대로 실행되는가?’ 였다. 롤백을 시켜줄 거라면 rollbackFor를 작성해 달라고 하였다. rollbackFor가 어떤 역할을 하는가? 분석하게 되었다.
rollbackFor는 해당하는 익셉션이 발생했을때 롤백을 시켜줄지 결정해주는 언노테이션이다.
기본적으로 스프링 프레임워크에서 @Transactional 언노테이션은 Checked Exception에 대해서는 롤백을 시키지 않도록 설계되어 있다. 그 이유는 스프링 프레임워크가 EJB의 습관을 따르기 때문이다.
때문에, checkException의 종류인 IOException, Exception등등 CheckedException에 대해서는 트랜잭션이 작동하지 않는것이다.
이를 해결해 주기 위해(트랜잭션을 잘 작동시키기 위해서)는 rollbackFor에 exception을 달아준다.

noRollbackFor

보통 Service에서, @Transactional을 사용해서 여러매소드를 하나의 트랜잭션으로 작동한다.
이렇게 사용하게 될 시 @Transactional이 다른 @Transactional을 호출하게 되면 호출된 트랜잭션은 호출한 트랜잭션에 병합이되고, 호출한 트랜잭션에서 에러가 발생할 경우, 호출당한 트랜잭션도 롤백처리가 되게 된다. 이때, 특정 작업에대해서 롤백을 시켜주지 않기위해 noRollbackFor를 사용한다.

timeout

지정한 시간 내에 해당 메소드 수행이 완료되지 않은 경우 JpaSystemException 을 발생한다.
기본값은 : -1
사용방법 : @Transactional(timeout = 1)
JpaSystemExceptionRuntimeException 을 상속 받기 때문에 롤백처리된다.
초단위로 지정할 수 있으며 -1인 경우 timeout을 지원하지 않는다.

readOnly

기본값은 false 이며 true로 세팅하는 경우 트랜잭션을 읽기 전용으로 insert, update, delete가 되지 않는다.
참고 :