작은 지식주머니
spring @Transactional 본문
!개인 공부용 입니다. 다소 틀린점 부족한점이 있을 가능성이 농후 합니다.
공부중 @Transactional 사용시 readOnly를 사용하면 필요없는 연산이 줄어든다. 라는 이야기를 들었는데
@Transactional 에 대해서 간단히는 알고있지만 항상 정확한 뜻과 기능들을 대강 알고 넘어간 느낌이라
구글을 뒤져가면서 대충 제가 읽을려고 작성하였습니다.
Transactional 이란 '거래' 라는 뜻을 가지고 있습니다.
스프링에서 Transactional는 데이터의 상태가 변경하는 작업을 실행 시 한번에 처리가 된다는 뜻을 가지고 있습니다.
예를 들어 한 유저를 만든다고 가정하였을 때 만약 에러가 발생한다면 지금까지의 행동을 전부 롤백시키고
작업 전 상태로 되돌린다는 뜻입니다.
SPRING에서는 어떻게 써야하는가
- DB와 관련된, 트랙잭션이 필요한 서비스 클래스 또는 메서드에 @Transactional 를 붙이면 된다.
- 클래스, 메서드 전부 @Transactional 선언 시 메서드의 @Transactional 이 우선시 된다.
- @Transactional 가 붙은 메서드 중 하나라도 작업이 실패시 전 작업이 취소되고 롤백이 된다.
- @Transactional 사용시 프록시 객체가 생성되어 commit 혹은 rollback을 진행해준다.
TEST 환경에서 @Transactional 는 어떻게 사용되는가?
- 테스트 메서드에 @Transactional 를 붙이게 되면 모든 작업이 끝난 후 전부 롤백이 된다.
- 만약 테스트 환경에서 롤백을 원하지 않을 떄 나는 @Rollback(false)를 사용했다.
더 좋은 방법이 있을 것 같은데 만약 알고 있다면 댓글로좀 부탁합니다..
- 만약 테스트 환경에서 롤백을 원하지 않을 떄 나는 @Rollback(false)를 사용했다.
트랜잭션은 4가지 속성을 가지고 있다.
- 원자성
- 한 트랜잭션 내에서 실행한 작업들은 하나의 단위로 처리된다. 전부 성공 or 전부 실패
- 일관성
- 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다. 데이터 무결성 만족 등.
- 격리성
- 동시에 실행되는 트랜잭션들이 서로 영향을 끼치지 않도록 격리되어야한다.
- 영속성
- 트랜잭션의 작업이 끝나면 결과가 전부 저장되어야 한다.
@Transactional 옵션
- isolation
- 트랜잭션에서 일관성없는 데이터 허용 수준을 설정
EX) -
DEFAULT = DB의 Isolation Level을 따라감@Transactional(isolation=Isolation.DEFAULT) public void addUser(UserDTO dto) throws Execption { }
READ_UNCOMMITED (level 0) : 커밋되지 않는 데이터에 대한 읽기를 허용
사용자가 A라는 데이터를 B라는 데이터로 변겅하는 동안 다른 사용자는 B라는 아직 아직 완료되지 않은 데이터 B를 읽을 수 있다. 또한 일반적으로 사용하지 않는다.
-Dirty Read, Non-repeatable read, Phantom read 현상이 발생
READ_COMMITED (level 1) : 커밋된 데이터에 대해 읽기 허용어떠한 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터에 접근 X
-Dirty Read 방지
REPEATABLE_READ (level 2) : 동일 필드에 대해 다중 접근 시 모두 동일한 결과를 보장- 트랜잭션이 완료될 떄까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸려
다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능함. - 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제가 불가능 하기 떄문에 같은 데이터를 두 번 쿼리했을 떄 일관성 있는 결과를 리턴한다.????
트랜잭션 시작 전 커밋된 내용만 조회가 가능
한 트랜잭션 내에서 수 차례 SELECT문을 수행하더라도 동일한 값이 읽혀지는 것을 보장
Phantom Read 부정합이 발생할 수 있다. - Phantom Read 부정합이란?
- SELECT ~~ FOR UPDATE 쿼리의 경우 다른 트랜잭션에서 수행한 변경 작업에 의해
레코드가 보였다가 갑자기 안보였다가 할 수있다. 이것을 Phantom Read이라고 한다.
- SELECT ~~ FOR UPDATE 쿼리의 경우 다른 트랜잭션에서 수행한 변경 작업에 의해
- 트랜잭션이 완료될 떄까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸려
- SERIALIZABLE (level 3) : 가장 높은 격리, 성능 저하의 우려가 있음.
- 데이터의 일관성 및 동시성을 위해 MVCC를 사용하지 않음.
- MVCC란 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시 LOCK을
사용하지 않고 데이터의 버전을 관리해 데이터의 일관성 및 동시성을 높이는 기술
- MVCC란 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시 LOCK을
- 트랜잭션이 완료될 떄까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸려
다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능 하다.
Phantom Read를 방지 가능
- 데이터의 일관성 및 동시성을 위해 MVCC를 사용하지 않음.
- 트랜잭션에서 일관성없는 데이터 허용 수준을 설정
- 레벨이 높아질 수록 데이터 무결성을 유지할 수 있지만 레벨이 올라감에 따라 DB의 성능이 떨어지고
비용이 높아지기 때문에 최대한 효율적인 방안을 찾아서 사용하는 것이 중요하다.
- propagation
- 트랜잭션 동작 도중 다른 트랜잭션을 호출할 떄 어떻게 할 것인지 지정하는 옵션
EX) -
@Transactional(propagation=Propagation.REQUIRED) public void addUser(UserDTO dto) throws Exception { // 로직 구현 }
- REQUIRED (Default)
- 이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고 진행중이 아니라면 새로운 트랜잭션을 생성.
- REQUIRES_NEW
- 항상 새로운 트랜잭션을 생성. 이미 진행중인 트랜잭션이 존재한다면 잠깐 보류.
해당 트랜잭션 작업을 우선시
- 항상 새로운 트랜잭션을 생성. 이미 진행중인 트랜잭션이 존재한다면 잠깐 보류.
- SUPPORT
- 이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 없다면 트랜잭션을 생성하지 않음.
- NOT_SUPPORT
- 이미 진행중인 트랜잭션이 있다면 보류하고 트랜잭션 없이 작업을 수행.
- MANDATORY
- 이미 진행중인 트랜잭션이 있어야만 작업을 수행 없다면 Exception을 발생
- NEVER
- 트랜잭션이 진행중이지 않을 떄 작업을 수행. 트랜잭션이 있다면 Exception 발생
- NESTED
- 진행중인 트랜잭션이 있다면 중첩된 트랜잭션이 실행되며, 존재하지 않으면
REQUIRED와 동일
- 진행중인 트랜잭션이 있다면 중첩된 트랜잭션이 실행되며, 존재하지 않으면
- 트랜잭션 동작 도중 다른 트랜잭션을 호출할 떄 어떻게 할 것인지 지정하는 옵션
- noRollbackFor
- 특정 예외 발생 시 rollback 작업을 하지 않는다.
-
@Transactional(noRollbackFor=Exception.class) public void addUser(UserDTO dto) throws Exception { // 로직 구현 }
- rollbackFor
- 특정 예외 발생 시 rollback
-
@Transactional(rollbackFor=Exception.class) public void addUser(UserDTO dto) throws Exception { // 로직 구현 }
- timeout
- 지정한 시간 내에 메소드 수행이 완료되지 않는다면 rollback (-1일 경우 timeout을 사용하지 않음.)
- Default = -1
-
@Transactional(timeout=10) public void addUser(UserDTO dto) throws Exception { // 로직 구현 }
- readOnly
- 트랜잭션을 읽기 전용으로 설정 , Default = false,
true시 insert, update, delte 실행 시 Exception 발생 -
@Transactional(readonly = true) public void addUser(UserDTO dto) throws Exception { // 로직 구현 }
- 트랜잭션을 읽기 전용으로 설정 , Default = false,
항상 부족합니다. 부족한 내용이 있다면 걍 쌍욕박고 피드백 해주시면 감사하겠습니다.
REFERENCE
https://velog.io/@kdhyo/JavaTransactional-Annotation-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90-26her30h
https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation
https://hyunki1019.tistory.com/111
https://devlog-wjdrbs96.tistory.com/422
'TID (Today I Do)' 카테고리의 다른 글
CRA 없이 직접 React 빌드해보기. (0) | 2023.07.27 |
---|---|
JAVA 기술 면접 대비 (0) | 2022.02.24 |
CORS란? (0) | 2022.01.27 |
REST 개념공부 (0) | 2022.01.25 |
Comments