데이터베이스는 모든 가능한 Schedule 이 Conflict Serializable 또는 View Serializable 하도록 보장해야 한다.
또한 스케줄은 Recoverable 해야하고, 가능하면 Cascadeless 이어야 한다.
Serializable 한 스케줄은 자동적으로 복구 가능하지만 , 동시성이 떨어지기 때문에 더 높은 성능을 얻으려면 동시성 제어가 필요하다.
병행성 제어는 여러 트랜잭션들이 동시에 실행될 때 데이터베이스의 일관성을 유지하면서도 동시성을 최대화하려는 방법
주요 목표
충돌 직렬화 가능성(Conflict Serializability) 또는 뷰 직렬화 가능성(View Serializability) 보장
복구 가능성(Recoverable) 보장
캐스케이딩 롤백 방지(Cascadeless) 보장
병행성 제어 프로토콜은 선행 그래프(Precedence Graph)를 직접 사용하지 않는다
선행 그래프(Precedence Graph)는 트랜잭션 간의 의존 관계를 시각적으로 나타내는 데, 트랜잭션들이 충돌하는 연산들을 시각적으로 나타낸다.
병행성 제어 프로토콜은 선행 그래프를 직접적으로 생성하면서 실행하지 않는다. 대신 정해진 규칙에 따라 트랜잭션들이 충돌을 피하고, 충돌이 발생하지 않는 직렬화 가능한 스케줄만 허용되도록 한다.

Serializalbe 이 가장 높은 등급은 일관성을 보장하고 , Read uncommitted 는 가장 높은 동시성을 보장한다.
트랜잭션이 다른 트랜잭션의 커밋되지 않은 변경을 읽을 수 있다. 이 격리 수준은 가장 낮은 격리 수준으로, 더 많은 동시성을 제공하지만, 일관성 문제가 발생할 수 있다. - EX) Dirty Read
트랜잭션이 다른 트랜잭션이 커밋한 데이터만 읽을 수 있게 한다. 이는 Dirty Read를 방지하지만, Non-repeatable Read가 발생할 수 있다. 예를 들어, 하나의 트랜잭션이 데이터를 읽고, 다른 트랜잭션이 그 값을 변경한 후 첫 번째 트랜잭션이 다시 같은 데이터를 읽을 때 다른 값을 얻게 될 수 있다.
같은 데이터를 두 번 읽을 때 그 사이에 다른 트랜잭션이 해당 데이터를 변경
동일한 select 문에도 다른 결과 발생 가능 -> 한 데이터(레코드)의 일관성이 깨짐
트랜잭션이 읽은 데이터를 다시 읽을 때 동일한 값을 읽을 수 있도록 보장한다. Non-repeatable Reads는 방지되지만, Phantom Read 가 발생할 수 있다.
이미 읽은 데이터의 '값'에는 변함이 없음
그러나 데이터 자체가 삭제되거나 추가될 수는 있음
가장 높은 격리 수준으로, 트랜잭션 간에 완전한 순차적 실행을 보장한다. 다른 트랜잭션은 서로 겹치지 않게 실행되며, Phantom Reads와 Non-repeatable Reads가 모두 방지된다. 그러나 이 설정은 동시성을 크게 제한하고 성능에 큰 영향을 미칠 수 있다.
Serializable 의 이외의 Isolation 에서는 전부 Serializable 한 결과 보장 X
NO Dirty Read , No Repeatable Read , No Phantom Read
트랜잭션이 시작되는 순간, 데이터베이스는 그 시점의 데이터 상태를 사진 찍듯이 '스냅샷'으로 캡처하여 해당 트랜잭션에게 보여준다.
완전한 격리: 트랜잭션이 실행되는 동안, 다른 사용자가 데이터를 수정하거나 삭제하더라도 이 트랜잭션은 영향을 받지 않게 된다. 오직 자신이 시작할 때 찍어둔 스냅샷(과거 시점의 데이터)만 보고 작업을 수행합니다. 이는 읽기 작업이 쓰기 작업을 차단하지 않고, 쓰지가 작업도 읽기 작업을 차단하지 않는다.
트랜잭션 T가 작업을 마치고 저장(Commit)하려 할 때, 가 변경한 모든 내용은 한꺼번에 반영되어야 합니다.
스냅샷 격리는 기본적으로 서로 다른 데이터를 건드리는 트랜잭션들을 동시에 잘 처리하지만, 같은 데이터를 동시에 수정하려고 할 때 Conflict 가 발생할 수 있다.
트랜잭션 T가 커밋을 시도할 때 (커밋 시점),T가 시작된 이후에 다른 트랜잭션이 이미 해당 데이터를 수정하고 커밋해버렸는지 확인한다.
만약 누군가 먼저 데이터를 수정했다면, T는 자신의 스냅샷이 최신 상태가 아님을 깨닫고 작업을 중단(Abort/Rollback) 시킨다. 내 스냅샷 버전 이후로 데이터가 변했다면 나는 쓸 수 없다는 규칙을 강제하여 갱신 손실을 막는다.

T1.commit -> y=1이 데이터베이스에 성공적으로 등록이 완료되었다는 의미
T2.Start -> 트랜잭션 시작 x = 0 , y = 1 읽음
T3. Commit-> x=2 , z=3
T2 에서 X=2 를 쓸려고 할때 서로 충돌이 발생한다.
이때의 교통정리 방식을 정의한 것.
First-Commit Win -> T2 abort
First-Updater-Wins는 데이터를 수정하려는(Update) 때 (Update 시점) 검사를 수행한다.
기존의 First-Committer-Wins는 트랜잭션 내내 열심히 계산하고, 마지막에 COMMIT 버튼을 누르는 순간 "앗, 늦었네?" 하고 죽는다. (낭비가 심함)
하지만 First-Update Win 은 Write 작업시 Write Lock 을 걸고 변경
T3 에서 x에 락을 걸고 쓰기 수행 , T2에서도 락을 얻을 수는 있지만 이미 변경되어있는 변수에 대해서 락을 얻는 것은 의미가 없다.
Reading is never blocked
Performance similar to Read Committed
avoid the usual anomalies

T1 , T2 동시에 진행되는 사진을 보자.
T1 은 a = 17 , b= 17 , T2 는 a= 3, b =3 이 된다
Write 실행하면 A 는 17 , B = 3 이 된다.
T1 이후 T2 (seralize ) 하게 이루어지면 A = 17 , B = 17 이 된다
T2 이후 T1 (seralize ) 하게 이루어지면 A = 3 , B = 3 이 된다
모든 결과가 다 다르다. 그러므로 Snapshot 은 Serialzable execution 이 되지 않을수 있다.
이를 Write Skew 라고 한다.
비관적 동시성 제어 (Locking, 2PL):"누가 끼어들 것 같아." 가 를 읽을 때 아예 Lock(잠금)을 걸어버립니다.T_3는 T_2가 끝날 때까지 X를 건드리지 못하고 대기(Wait)합니다.
낙관적 동시성 제어 (Snapshot Isolation, MVCC): 설마 겹치겠어? 일단 각자 해봐. Lock 없이 빠르게 진행합니다.나중에 검사해보니 겹쳤네? 늦게 온 놈(T_2)이 재시도해. (First-Committer-Wins)