고딩왕 코범석
트랜잭션에 대해 알아보자. 본문
오늘은 트랜잭션에 대해 정리해보자
왜 정리하려는건데?
며칠 전 면접을 볼 때 면접관님께서 내 프로젝트에 관한 질문을 하셨다.
"왜 비즈니스 로직을 컨트롤러에 담으셨어요?"
(만약 취업을 위해 국비지원 학원을 알아보시는 분들 꼭 잘 조사하고 가세요... 강사한테 지식 잘못 배우면 향후 여파가 커집니다!)
젠장... 학원 수료하고 따로 스프링에 대해서 공부했는데 비즈니스 로직은 @Service에 작성하는게 맞더라...
"그렇다면 트랜잭션으로 로직을 처리할 때 장단점이 뭐가 있을까요?"
고딩좌 킹범짱 : "단점은 아무래도 잘못된 로직이 있을 경우에는 데이터베이스에 반영되지 않습니다!"(아주 자신있게)
"그건 장점아닌가요??"
꿀먹은 고딩좌 킹범짱 : ......(정식 면접이 끝난 후 질문했다.) @Transactional의 단점이 무엇인가요??
"해당 @Transactional의 로직이 복잡하고 요청이 많아진다면 서버에 부하가 걸리겠죠?"
그런 의미로 @Transactional을 공부해보자
그전에 먼저 트랜잭션을 알아야지?
데이터베이스 공부할 때 자주 들었던 용어다.
정의 : 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위
예를 들면!
내가 어떤 쇼핑몰에서 상품을 구입했다. 상품에 대한 구매완료 버튼을 누르고 나서 처리되는 작업을 상상해보자면
- 내 주문서에 주문한 상품이 들어있다.
- 해당 상품의 재고가 내가 주문한 수량만큼 깎인다.
이 정도로 간단하게 생각해보자면 내가 구매완료 요청을 누르고 나서 벌어지는 여러 작업들을 하나의 작업단위라 보면 되겠다.
또 성질이랑 상태도 알아봐야겠지?
Atomicity(원자성)
트랜잭션의 연산은 DB에 반영이 되던지, 전혀 반영이 되지 않던지!
트랜잭션 내의 모든 명령은 완벽히 수행해야한다. 하나라도 오류 발생 시 전부 취소!
Consistency(일관성)
- 트랜잭션이 실행을 성공적으로 완료시 언제나 일관성 있는 DB 유지
Isolation(독립, 격리성)
- 한 트랜잭션이 수행중일 때, 다른 트랜잭션이 수행중인 트랜잭션의 결과를 참조하거나 끼어들 수 없다.
Durability(영속, 지속성)
- 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.
Commit
- 한 트랜잭션의 모든 작업들이 끝나고 DB가 일관된 상태에 있을 때 해당 트랜잭션이 완료된 것을 트랜잭션 관리자에게 알려준다.
Rollback
- 트랜잭션 처리가 비정상적으로 처리되고 종료되어 DB의 일관성을 깨뜨렸을 때, 원자성을 위해 이 트랜잭션이 수행한 모든 작업을 취소한다.
오케이 그럼 Spring에서 어떻게 사용하는데?
코드 기반 트랜잭션 처리 및 선언적 트랜잭션을 지원한다. 주로 선언적 트랜잭션을 이용하는데 어노테이션인 @Transactional로 선언하는 법, tx:advice태그로 선언하는 법이 있다.
@Transactional
일반적으로 스프링에서는 Service 레이어에서 메소드에 @Transactional 을 추가하여 트랜잭션 처리를 한다. 주로 DML(create, update, delete)에 쓰이면 효과적이겠지?
스프링 트랜잭션의 성질
1. 쓰레드가 다르면 다른 트랜잭션이 생성된다.
2. 트랜잭션 롤백과 예외
3. 트랜잭션 전파(PROPAGATION)
트랜잭션 안에서 다른 트랜잭션을 메소드를 호출할 때는 어떻게 해야할까??
- PROPAGATION_REQUIRED (default)
- 부모 트랜잭션 존재시 부모 트랜잭션에 참가한다.
- 부모 트랜잭션이 없을 경우 새 트랜잭션을 시작한다.
- PROPAGATION_SUPPORTS
- 부모 트랜잭션 존재시 부모 트랜잭션에 참가한다.
- 부모 트랜잭션이 없을 경우 트랜잭션이 없는 것 처럼 동작
- PROPAGATION_MANATORY
- 부모 트랜잭션 존재시 부모 트랜잭션에 참가한다.
- 부모 트랜잭션이 없을 경우 예외가 발생한다.
- PROPAGATION_REQUIRES_NEW
- 부모에 상관 없이 새 트랜잭션을 시작
- 부모 트랜잭션이 있다면? 부모 트랜잭션 중지!
- PROPAGATION_NOT_SUPPORTED
- 부모 트랜잭션에 유무에 상관 없이 트랜잭션 없이 동작
- 부모 트랜잭션이 있을 경우 부모 트랜잭션 중지
- PROPAGATION_NEVER
- 항상 트랜잭션 없이 동작, 부모 트랜잭션 존재 시 예외 발생
- PROPAGATION_NESTED
- 부모와 독립적이다. 독립적으로 롤백되거나 커밋될 수 있다.
4. 트랜잭션 격리수준(ISOLATION)
트랜잭션 간의 격리성을 완벽히 보장하면 동시성 처리 성능이 매우 나빠진다.
그렇다면 일관성이 없는 데이터를 어느정도로 허용하는가?
- DEFAULT : 기본설정, DB의 ISOLATION LEVEL을 따른다.
- READ_UNCOMMINTTED (level 0) : 커밋되지 않은 데이터에 대한 읽기를 허용한다.
- 누가 데이터를 변경하는 도중에 그 값을 참조할 수 있겠지??
- READ_COMMITTED (level 1) : 트랜잭션이 커밋이 확정된 데이터만 읽기를 허용한다.
- READ_UNCOMMINTTED 상황과 비교해보자. 누가 데이터를 변경하는 동안에는 그 데이터에 접근을 할 수 없다.
- REPEATABLE_READ (level 2) : 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 SHARED LOCK이 걸리므로 다른 사용자는 그 영역에 해당하는 데이터에 대한 수정이 불가능
- 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때 까지 후행 트랜잭션이 갱신, 삭제가 불가능하기 때문에 일관성 있는 결과를 가져올 수 있다.
- SERIALIZABLE (level3) : 동시성 부작용을 방지하지만 순차적인 호출진행이기 때문에 액세스 속도가 가장 낮다,
잘못된 정보가 있거나 부족한 점이 있다면 꼭 댓글 남겨주세요!
출처
'Language & Framework > Spring' 카테고리의 다른 글
@Async, 비동기 기능 (0) | 2021.02.16 |
---|---|
ResponseEntity란? (4) | 2021.02.08 |
JUnit과 계층별 단위 테스트 정리 (0) | 2021.01.31 |
의존관계 주입(Dependency Injection) (0) | 2020.11.19 |
DTO란? (0) | 2020.10.30 |