동시에 여러 트랜잭션이 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수
있도록 허용할지 말지를 결정하는 것.
하나의 트랜잭션이 공유자원에 접근하는 동안 다른 트랜잭션이 아예 접근을 못하게 하는 것이 아니라 Level을
나누어 접근 허용도를 조절하는 것이다.
트랜잭션 격리 수준은 어떤게 있을까?
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
MySQL과 Microsoft SQL Server(MSSQL)는 ANSI/ISO SQL 표준에 정의된 4가지 격리 수준을 기본적으로 지원한다.
추가적으로 데이터베이스에 따라 지원하는 다른 레벨이 존재할 수 있으나
보편적으론 이 4가지를 기본으로 지원한다.
READ UNCOMMITTED
각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있다.
정합성에 문제가 많은 격리 수준이기 때문에 사용하지 않는 것을 권장한다.
아래의 그림과 같이 Commit이 되지 않는 상태지만 Update된 값을 다른 트랜잭션에서 읽을 수 있다.
그렇다면 READ UNCOMMITTED는 문제가 없을까?
DIRTY READ현상 발생
트랜잭션이 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상
ex) A가 데이터 3을 업데이트하는 트랜잭션이 있다.
처음에 3을 더하고 그다음 3을 곱하는 로직이 있다고 가정한다.
그럼 트랜잭션이 끝나면 18로 데이터가 변해있어야 한다.
그러나 Read Uncommitted 레벨로 지정하면 트랜잭션이 끝나기 전(Committed)에 조회가 가능하다
즉 3을 더한 시점 조회를 한다면 데이터가 6나올 것이고 다시 조회하면 18이 나올 것이다.
무결한 데이터 18이 나오지 않으니 결함 있는 데이터를 읽어서DIRTY READ
그런데 트랜잭션이 중간에 예외가 발생하여 롤백 된다면??!!
mssql에는 전체 트랜잭션 레벨을 설정하는 것이 아닌 특정 쿼리의 실행을 도와주는 방법인 "힌트"로써 withnolock이 존재한다.
READ COMMITTED
RDB에서 대부분 기본적으로 사용되고 있는 격리 수준이다.
Dirty Read와 같은 현상은 발생하지 않는다.(Committed 된 데이터만 읽을 수 있음으로)
실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.
Read Committed는 Committed 되기 전에는 조회가 불가능 한 것이 아니다.Committed되기 전의 원본 데이터는 Undo 영역에서 읽어오고Committed 된 이후에는 바뀐 실제 데이터를 조회할 수 있도록 하는 것이다.
그렇다면 Undo는 무엇인가?
GPT A: Undo는 데이터베이스 시스템에서 데이터의 원래 상태로 롤백하는 메커니즘입니다. 트랜잭션 중에 변경된 데이터에 대한 원래의 값이 Undo 로그 또는 버퍼에 저장되며, 트랜잭션이 실패하거나 롤백될 경우 이 Undo 정보를 사용하여 데이터를 원래 상태로 복원합니다.
데이터가 실제 DB에 반영되기 전에 원본 데이터를 Undo 영역에 넣고 바뀔 데이터는 쓸 준비를 한다. 트랜잭션 특성상
트랜잭션에서 예외가 발생하면 모든 데이터를 순차적으로 되돌려야하기 때문에 Undo 로그에 원본데이터를 저장하여
다른 트랜잭션이 읽기를 원할 경우 Undo 영역의 데이터를 제공할 수 있다.
이는 MVCC(Multi-Version Concurrency Control)과도 연관되어 있지만 나중에 이야기 하기로 하자.
그렇다면 READ COMMITTED는 문제가 없을까?
트랜잭션1이 Commit한 이후 아직 끝나지 않는 트랜잭션2가 다시 테이블 값을 읽으면 값이 변경됨을 알 수 있다.
하나의 트랜잭션내에서 똑같은 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 하는 REPEATABLE READ의 정합성에 어긋난다.
UNREPEATABLE READ는 Read Committed에서 나올 수 있는 문제인데, 쉽게 말해 한 트랜잭션 안에서 연속적으로 읽었을 때, 같은 값이 안 나온다는 문제이다. 읽기 성능을 향상 시키기 위해 특정 트랜잭션이 읽고 있는 도중에 Update가 가능하기에 생기는 문제이다. 왜냐하면 Comitted된 값만 읽겠다는 규제만 존재하기 때문
이러한 문제는 주로 입금, 출금 처리가 진행되는 금전적인 처리에서 주로 발생한다.
데이터의 정합성은 깨지고, 버그는 찾기 어려워 진다.
REPEATABLE READ
따라서 한층 더 엄격한 룰을 추가한다. 특정 트랜잰션이 공유자원을 점유 시, 조회만 가능하다!
간단하게 말하자면 위의 UNREPEATABLE READ의 문제를 해결하기 위해 같은 트랜잭션 안에서 재차 반복적으로
읽어도 같은 값이 나올 수 있도록 SharedLock(공유 락)을 거는 것이다.
다른 트랜잭션이 공유자원일 읽는 와중에 Update가 가능하여 문제가 난 것이기에 이를 해결 하기 위해 조회를 할 경우
다른 트랜잭션이 Update를 못하게 하는 것 바로 Repeatable Read이다.
Repeatable Read는 mysql과 mssql 둘 다 있지만 매커니즘이 조금씩 다르다.
둘 다 먼저 들어온 트랜잭션이 공유자원을 점유하면Select는 가능하지만Update는불가능 하게 하기에 같은 값을
제공하지만 Mysql은 특정 트랜잭션이 공유자원을 점유 시 버전을 다르게 관리하여 (MVCC) 한 데이터의 변경이
일어나더라도 해당 버전 외부(트랜잭션 밖)에는 보여지지 않는다.
그러나 Mssql은 단순히 Update만 블로킹 하고 Insert와 Delete는 블로킹 하지 않는다. 따라서 트랜잭션 안에서 데이터가
추가되거나 삭제되는 데이터가 보일 수 있다.
MySQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다.