-
read committed 격리수준이라면 , dirty read/write 문제가 해결된다
- dirty read: 아직 커밋되지 않은 다른 트랜잭션의 데이터를 읽는 것.
- dirty write:아직 커밋되지 않은 다른 트랜잭션의 데이터를 덮어 쓰는것.
-
read committed 수준이라도 동시성 문제는 사라지지 않는다.
- A 트랜잭션이 열려있고, 다른 트랜잭션 B 가 완료되었을 때 A 가 트랜잭션이 열린 시점의 데이터가 아니라 B 트랜잭션의 커밋결과를 반영하면 문제가 생긴다.
- 가령 나의 계좌 2개에서 총 금액을 합하는 트랜잭션이 A였을 때. 계좌 2개가 각각 500원이 있었다. 현실에는 1000원이 있는 셈.
- 근데 A 트랜잭션이 열리때 하나의 계좌에서 500원을 읽고, B 트랜잭션이 두번째 계좌에서 금액을 첫번째 계좌로 옮겨 400원이 되었다면, A 트랜잭션이 두번째 계좌를 읽으면 400원이 있고 따라서 A 트랜잭션은 500(B 트랜잭션 반영 전 첫번째 계좌) + 400 (B 트랜잭션 반영 후 두번째 계좌) 는 900원이라는 잘못된 금액을 나타낸다.
- 이런 현상을 nonrepeatable read( read skew ) 라고 한다.
-
nonrepeatable read( read skew ) 를 방지하기 위한 흔한 방법이 스냅샷 격리다.
- 트랜잭션을 시작할 때 커밋된 상태였던 모든 데이터 상태를 본다. 데이터가 나중에 다른 트랜잭션에 대해 바뀌더라도, 각 트랜잭션은 특정한 시점의 과거 데이터를 볼 뿐이다.
- 결국 다중 버전 동시성 제어라는 기법을 사용하는데, 데이터베이스가 객체의 여러 버전을 유지하는 것이다.
-
동시에 트랜잭션이 갱신하면 흔히 손실이 발생한다. lost update
- 결국 read - modifiy - write 주기에서 읽을 떄와 쓸 때 간극에 여러 트랜잭션이 관여하면 발생한다.
- 가령 아래와 같은 원자적 쓰기(atomic operation, increment) 코드를 쓰면 동시성 안전(concurrency safe)하다.
UPDATE A SET c = c + 1 WHERE key = 'foo';
- read modify write 주기가 순차적으로 실행되도록 강제하거나, 대안으로는 갱신손실을 발견하면 abort 하고 재시도하도록 하는 방법이 있다.
- 데이터 베이스 중에서는 원자적 compare and set 연산을 제공하는 것도 있다.
UPDATE a SET b = 'foo' WHERE id = 1234 and foo='bar';
-
read skew 와 비슷하게 write skew 도 존재한다.
```java
// 트랜잭셔 시작
A) 현재 당직 의사가 2명 이상이라면, B)당직의사를 한명 제거할 수 있다.
// 트랜잭셔 끝
A 조건으 두 트랜잭션이 동시에 통과하고 B 를 진입하는 경우.
```
- 격리수준은 이해하기 어렵고, 디비마다 구현에 일관성이 없다. 반복 읽기는 의미는 상당히 다양하다.
- 디비를 단일 스레드 루프에서 실행가능하게 하여 동시성 문제를 해결하는 모델이 최근에 논의되고 있다.
- 비관적으로 혹은 낙관적으로 동시성을 제어할지는 성능과 정합성 사이의 트래이드 오프다.