트랜잭션
- 데이터 다룰 때 장애가 일어난 경우 데이터를 복구하는 작업의 단위가 된다.
- 여러 작업이 동시에 같은 데이터를 다룰 때 이 작업들을 서로 분리하는 단위가 된다.
수행 과정
동시성 제어(Currency Control)
- 공연 예매 시 좌석 선택에 있어서 사용자끼리 동시에 같은 좌석을 선택했을 때, 한 사람만 좌석이 예매 되어야 하고 남은 한 사람은 예매가 되지 않아야 한다.
- 여러 유저의 동시 접속 문제는 모든 서비스에서 일어날 수 있는 문제
- 동시성을 제어할 수 있도록
LOCK
기능과 SET TRANSACTION
사용하여 트랜잭션의 격리성 수준을 조정할 수 있다.
트랜잭션 격리 수준
- 여러 트랜잭션들이 동시에 처리될 때 트랜잭션끼리 얼마나 고립되어 있는 지를 나타내는 것
- 격리 수준에 따라 특정 트랜잭션이 다른 트랜잭션에서 변경한 데이터를 볼 수 있도록 허용할 지 말 지를 결정할 수 있다. 모두 LOCK 걸어버리면 동시에 수행되었던 트랜잭션들은 순차적으로 수행될 수 밖에 없으니 성능은 떨어지게 된다. 가장 효율적인 LOCKING 방법을 고민해야 한다.
Lock 종류
Shared Lock
공유 락
- 데이터 읽을 때 사용되는 락, 공유 락끼리 동시 접근 가능하다.
Exclusive Lock
베타 락
- 데이터 변경할 때 사용되는 락
- 트랜잭션이 완료될 때까지 유지되며 해당 락이 해제되기 전까지 다른 트랜잭션 접근이 금지된다.
격리수준 0 - Read uncommitted
- 트랜잭션 처리중에 읽는 것이 허용된다
- 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있다.
- 데이터 읽는 동안 해당 데이터에 공유 락이 걸리지 않는 계층이다.
문제점 Dirty Read
1번 A 계좌로 송금, 아직 커밋 전
2번 A계좌의 송금 후 금액 조회
-> 계좌 송금 중 롤백이 일어났을 때, 1번은 여전히 이전 금액이지만 2번은 송금 후 금액 조회된다.
격리수준 1 - Read committed
- 하나의 트랜잭션이 처리되는 동안 다른 트랜잭션 접근할 수 없다.
커밋 후 가능
- 데이터를 읽는 동안 해당 데이터에 공유 락이 걸리는 계층
문제점 Non-repeatable read
- 한 트랜잭션이 처리되는 동안 특정 값을 조회할 때 다른 값이 조회되는 현상
REPEATABLE READ의 정합성에 어긋난다
- 트랜잭션 1이 계좌를 조회했을 때 잔고가 10000원
- 트랜잭션 2에서 A계좌로 송금을 완료해 커밋하여 잔고가 10000 → 20000원이 되었을 때
-> 트랜잭션 1이 다시 잔고를 조회하면 10000원이 아니라 20000원이 된다.
격리수준 2 - Repeatable Read
- 트랜잭션이 처리되는 동안 한 번 조회한 데이터의 내용이 항상 동일함을 보장한다.
-> 다른 트랜잭션은 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호의 처리가 끝나기 전까지 해당 데이터를 수정할 수 없다.
- 한 트랜잭션이 완료될 때까지 SELECT 쿼리가 사용되는 모든 데이터에 공유 락이 걸리는 계층이다.
- 데이터를 수정할 때는 Undo 공간에 백업해 두고 실제 레코드 값을 변경한다.
- 백업 데이터는 불필요 하다고 판단되는 시점에 주기적으로 삭제한다.
- 백업 레코드가 많아지면 성능이 저하될 수 있다.
- 이러한 변경 방식을 MVCC(Multi Vercion Concurrency Control)이라 부른다.
- 단점은 INSERT/DELETE문에 대한 정합성이 보장되지 않는다는 점이다
문제점: Phantom Read
- 원래 있던 데이터가 사라지거나 혹은 생기는 현상이 발생할 수 있다.
- 1번 트랜잭션이 특정 계좌에서 2억 원을 조회했었는데 2번 트랜잭션이 롤백하면 해당 데이터는 사라지기 때문이다.
격리수준 3 - Serializable
- 가장 엄격한 격리 수준
- 한 트랜잭션이 SELECT 쿼리를 실행해 테이블을 읽으면 다른 트랜잭션은 해당 테이블에 대한 추가, 변경 또는 삭제를 할 수 없다.
문제점: 성능 저하
동시성 문제 해결 방법
1. 비관적 동시성 제어
- 시용자들이 같은 데이터를 동시에 수정할 것이라 가정한다.
- 데이터를 읽는 시점에 Lock(Repeatable Read 또는 Serializable) 걸고, 트랜잭션이 완료될 때까지 Lock 유지
- SELECT 시점에 Lock 걸기 때문에 심각한 성능 저하 초래 가능, wait, nowait 옵션과 함께 사용할 필요가 있다.
2. 낙관적 동시성 제어
- 사용자들이 같은 데이터를 동시에 수정하지 않을 것이라 가정한다.
- 데이터를 읽는 시점에 Lock 걸지 않으며, 수정 시점에 값이 변경 됐는지를 검사한다.