몇몇 데이터 타입과 함수는 트랜잭션 동작과 관련된 특별한 규칙이 있습니다.
smallserial
, serial
, bigserial
3가지 타입이 있고 이는 고유한 식별자를 만들기 위한 표현일뿐 실제 타입이 아닙니다.// 사용할 때
CREATE TABLE tablename (
colname SERIAL
);
// 동작
CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
SEQUCE를 생성하고 이를 특정 필드에 소유시켜 기본값으로 설정하는 형식입니다. 기본 값이기 때문에 다른 값을 임의로 삽입할 수 있고 소유하는 컬럼이 삭제될 경우 함께 삭제됩니다.Unique
혹은 Primary Key
제약 조건을 주지 않는다면 중복을 허용합니다.Sequnce
의 nextval
함수는 원자적으로 수행됩니다. 따라서 nextval 호출을 포함하는 트랜잭션이 롤백되더라도 sequance 값을 회수하지 않습니다.PSQL의 기본 격리 수준입니다.
SELECT문은 쿼리 시점 이전에 commit 된 데이터 혹은 같은 트랜잭션 내의 변경 사항만을 볼 수 있습니다. 2개의 질의 중간에 commit 된 데이터가 존재한다면 나중 질의에서는 조회가 될 수 있습니다.
UPDATE, DELETE, SELECT FOR UPDATE(or FOR SHARE)에서도 모두 질의는 동일하게 동작합니다.
아래 그림은 Read Commited Isolation Level에서의 동작을 표현하고 있습니다.
Client A
의 Insert로 인해 id=2
인 데이터가 생성되어도 Client B
에게는 노출되지 않습니다.Client B
의 트랜잭션 내 Insert된 id=3
인 데이터는 조회가 됩니다.Client B
의 트랜잭션이 Commit
되고 난 뒤에 Client A는 id=3
인 데이터를 조회할 수 있습니다.반복 읽기 격리 수준은 트랜잭션이 시작되기 전에 커밋된 데이터만 볼 수 있습니다. 트랜잭션이 진행되는 동안 커밋 되거나 아직 커밋 되지 않는 내용을 볼 수 없습니다. 같은 트랜잭션 내의 변경 사항을 볼 수 있습니다.
아래 그림은 Repeatable Read Isolation Level에서의 단순 읽기 동작을 표현하고 있습니다.
Client A
의 마지막 Select 에서도 Client B
의 Commit 된 데이터(id=3)
가 조회되지 않습니다.(phantom read 발생 x) 이전 Select 결과에 내부 트랜잭션에서 Insert된 데이터(id=2)
만 추가되어 조회 됩니다.아래 그림은 Repeatable Read Isolation Level에서의 같은 Row에 대한 동시 업데이트를 표현하고 있습니다.
Client B
의 Update
는 Client A
의 Update
와 같은 row
를 변경하려고 합니다. 이때 Client A의 lock에 의해서 대기
하게 됩니다.Commit 될 경우
, Client B의 Transaction은 에러([40001] ERROR: could not serialize access due to concurrent update
)와 함께 Rollback
됩니다.Rollback 될 경우
, Client B의 Transaction은 정상적으로 수행됩니다.반복 읽기 수준은 위와 같이 트랜잭션이 안정적으로 db를 제어하도록 보장하지만 항상 연속된 실행(serial)의 결과와 같은 결과를 보장하지는 않습니다. Write Skew
현상으로 트랜잭션 내부에서 문제 없이 의사결정되지만 트랜잭션의 결과가 결과적으로 논리적 제약사항을 위반하게 되는 것을 의미합니다. 대표적으로 의사 당직 문제가 있습니다.
의사 당직 문제: 의사는 최소 1명 이상 당직을 서야 합니다. 따라서 자신 외에 당직 의사가 1명 이상(자신을 포함해서 2명 이상) 있는 것은 확인하고 당직을 종료하게 됩니다.
UPDATE doctor
SET on_call = false
WHERE (2 <= SELECT count(id) FROM doctokrs WHERE on_call = true)
AND id = '1'
Client B
의 Transaction COMMIT 시에 ERROR가 발생합니다. 즉, psql에 직렬화 되지 않는 상황을 감지하고 트랜잭션을 취소 시킵니다.pg_locks
테이블에 SIReadLock
모드으로 보여집니다.https://www.postgresql.org/docs/15/transaction-iso.html
https://www.postgresql.org/docs/15/functions-sequence.html
https://www.postgresql.org/docs/15/datatype-numeric.html#DATATYPE-SERIAL