Open skarltjr opened 2 years ago
여러 클라이언트에서 동시에 자원에 접근하여 활용하려고 할 때 문제가 발생할 수 있다.
가장 쉬운 방법은 트랜잭션을 줄세워 차례대로 수행시키는거지만 성능상 매우 안좋다
따라서 트랜잭션을 서로 격리해서 다른 트랜잭션이 영향을 주지 못하게한다
Read uncommitted - 사실상 거의 사용하지 않는다
Read committed
repeatable read
serializable
dirty read
올바르게 처리되지 않은 데이터를 다른 트랜잭션에서 참조하는 경우 문제가 발생할 수 있다
dirty write
아직 처리되지 않은 데이터를 덮어쓰는 경우도 문제가 될 수 있다.
1. 커밋된 데이터만 읽기
- 커밋된 값과 트랜잭션 진행중인 값을 따로 보관
2. 커밋된 데이터만 덮어쓰기
- 행 단위 잠금 사용
- 같은 데이터를 수정하는 트랜잭션이 존재한다면 끝날때까지 대기 후 그 다음에 데이터를 수정하도록한다
그러나 여전히 문제는 존재
non-repeatable read 문제 발생
레벨1의 문제는 트랜잭션 진행동안 데이터가 변경되는 문제
-> 레벨2는 트랜잭션동안 같은 데이터를 읽게 한다
즉 Repeatable Read는 트랜잭션 진행동안 데이터가 변경되더라도 같은 데이터를 읽도록 해준다
- 읽는 시점에 특정 버전에 해당하는 데이터만 읽음
level2에서는 같은 데이터를 쓸 때 변경이 유실되는 경우를 막기위한 방법이 여러가지 존재
1. db가 제공하는 원자적 연산
ex ) update article set readCount = readCount+1 where id =.
2. 명시적 잠금
ex) select ... for update
-> 이 경우 조회 시 락을 걸고 변경 후 락을 해제
-> 즉 읽는동안 다른 트랜잭션에서 해당 데이터 읽기 및 수정 불가
⭐️서로 다른 데이터를 다루지만 논리적으로 race condition인 경우는?
이 문제는 a,b는 서로 다른 데이터를 다루지만 각 트랜잭션의 결과가 서로에게 영향을 미치는 문제
## serializable
calldata를 인덱스로 삼고 인덱스 잠금이 수행되는 상태라고 가정해보자
a는 먼저 update할 때 calldate를 인덱스로 잠금을 수행
b가 건드리고자하는 calldate 인덱스는 이미 잠겨있기에 동작 수행 실패
결국 이 문제
주제 : 원자성
트랜잭션이란
트랜잭션 범위는 ⭐️커넥션 기준
그럼 우리가 여러 트랜잭션을 단일 트랜잭션으로 묶고싶다면?
스프링의 @Transactional은 기본적으로 전파 레벨이 Required -> 이미 시작된 트랜잭션이 있다면 참여하고 없다면 새로 생성하여 시작
왼쪽 그림의 경우 외부api 호출에 실패하여 롤백처리 -> 큰 문제가 없다 -> 외부 서비스 호출이 실패했기에 외부 서비스에 영향을 주지 않고 현재 내가 수행한 명령어에 대해서 롤백처리만 하면 ok
-> 물론 왼쪽 그림도 문제가 없는건 아니다 -> 실제 외부 서비스가 잘 호출되었는데 그 응답을 받을 때 네트워크 문제로 응답만 못받은경우 롤백이 발생한다. -> 즉 이 경우는 외부 서비스가 잘 동작했음에도 롤백시키는 경우
오른쪽그림의 경우 문제가 될 수 있다 -> 이미 외부 서비스를 호출한 상태 / ex) 외부 결제 시스템을 통해 결제를 한 상태 -> 롤백을 수행할거면 외부 서비스에도 상태를 변화시킬 행동(복구)을 추가로 취해야한다
두 개 이상의 자원 (ex. db, mq)을 한 트랜잭션으로 처리
예를 들어 두 개의 db를 하나의 트랜잭션으로 묶는다던가, db-mq를 하나의 트랜잭션으로 묶는다던가
그런데! 거의 사용하지 않는다.