데이터베이스는 여러 사용자
가 같은 레코드
에 접근해서 데이터를 rw
하게 된다. 즉, 멀티 유저가 동일한 자원에 동시에 접근하므로 동시성 문제
가 필연적으로 발생할 수 밖에 없다. 특히 db 특성상 트랜잭션에 있어 데이터의 무결성이 보장 되는 것이 중요한데, 동시성 문제가 제대로 핸들링 되지 않을 경우 아래와 같은 문제들이 발생할 수 있다.
전제 : A 트랜잭션과 B 트랜잭션이 동일한 레코드 r에 접근한다고 가정하자.
Dirty Reads :
: A 트랜잭션에서 레코드 r을 읽어와서 작업
: B 트랜잭션에서 레코드 r을 update -> r'
: A 트랜잭션에서 다시 레코드 r'을 읽어와서 작업
: B 트랜잭션에서 다시 레코드 r'를 rollback ->r
위의 시나리오에서 A 트랜잭션 관점에서 봤을 때 시점에서 읽은 레코드은 시점에서 읽은 레코드 r'과 불일치 하게 된다. 즉, 레코드 r의 무결성이 깨졌다. A 입장에서는 clean한 값이 아닌 변경된 값(dirty)을 읽었으므로 dirty read
가 성립된다.
또한, B 트랜잭션은 실패하여 r'에서 r로 database 상태를 롤백 하는 것이 무결성이 깨지지 않는 조건인데, 트랜잭션 A 입장에서는 이미 값을 읽어버렸으므로 무결성은 이미 깨진 상태라고 할 수 있다. 그리고 해당 더러운 데이터가 커밋 된다면 데이터 오염
이 발생하게 된다.
Non-Repeatable Reads :
: A 트랜잭션에서 레코드 r을 읽어와서 작업
: B 트랜잭션에서 레코드 r을 update -> r'
: A 트랜잭션에서 다시 레코드 r'을 읽어와서 작업
하 트랜잭션 안에서 같은 데이터를 조회 했는데 값이 달라지는 현상. 위의 시나리오에서는 . Dirty read와 다른 점은 롤백 밖에 없어 보인다.
Phantom Reads :
: A 트랜잭션에서 레코드 r을 읽어와서 작업
: B 트랜잭션에서 r 조회 조건과 같은 레코드 insert -> q
: A 트랜잭션에서 다시 레코드 r,q를 읽어와서 작업
트랜잭션 A 관점에서는 시점에서 없었던 레코드 q가 새로 생겨서 팬텀 리드가 된다.
위의 동시성 문제
는 결국 트랜잭션들 사이의 isolation 레벨을 어떻게 관리하느냐의 문제가 된다. 여러 트랜잭션이 같은 레코드에 동시적으로 접근하는 걸 허용해서 성능을 향상 시킬지, 아니면 무조건적인 ACID를 보장 하여 데이터의 무결성을 지킬 것인지, 두 요건을 저울질 해서 개발자 각자의 판단으로 트랜잭션의 Isolation level을 아래와 같이 설정할 수 있다.
Read Uncommitted : 커밋 되지 않은 트랜잭션 사이의 read를 허용한다. 각 트랜잭션 프로세스 마다 마구잡이로 읽을 수 있으니까 온갖 문제가 생길 수 있다.
Read Committed : 커밋된 데이터만 조회 가능하다.Phantom Read와 Non-Repeatable Read가 발생 가능하다.
Repeatable Read : UndoLog로 MVCC(Multi-Version-Concurrency Control)을 한다. Non-repeatable read
는 막아주지만, phanton read
는 발생할 수 있다.
Serializable Read : 가장 엄격한 격리 수준으로 트랜잭션의 순차적 처리를 보장한다. SELECT 작업시 S-Lock을 걸어 삽입/수정/삭제 트랜잭션을 막아 버린다. 동시처리 성능을 희생하여 데이터의 무결성을 지키는 설정.
[1] https://mangkyu.tistory.com/288
[2] https://amazelimi.tistory.com/entry/DB-Dirty-Read-Non-Repeatable-Read-Phantom-Read-%EC%98%88%EC%8B%9C-%EB%B0%8F-Snapshot-Isolation-Level-LIM
[3] https://steady-coding.tistory.com/562