Transaction Isolation Level
์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐ ์ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋์ ํ๋ฉด ๊ฒฉ๋ฆฌ ์์ค์ ๋ํ ์ดํด๊ฐ ์์ฐ์ค๋ฝ๊ฒ ์๊ตฌ๋ฉ๋๋ค. ๊ฒฉ๋ฆฌ ์์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ACID ์ฑ์ง ์ค Isolation ์ ํด๋นํ๋ฉฐ, ์ฌ๋ฌ ํธ๋์ญ์ ์ด ๋์์ ๋ณ๊ฒฝ์ ์ํํ ๋ ์ฑ๋ฅ๊ณผ ์์ ์ฑ, ์ผ๊ด์ฑ ๋ฐ ์ฌํ์ฑ ๊ฐ์ ๊ทํ์ ๋ฏธ์ธํ๊ฒ ์กฐ์ ํ๋ ์ค์ ์ ๋๋ค. SQL:1992 ํ์ค์์ ์ ๊ณตํ๋ 4๊ฐ์ง ๊ฒฉ๋ฆฌ ์์ค์ ์ข ๋ฅ๋ ์๋์ ๊ฐ์ต๋๋ค.
READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
MySQL ์ InnoDB ๋ MVCC ์ 2-Phase Locking ์ ์ฅ์ ์ ์ ์ ํ ์กฐํฉํ์ฌ ํธ๋์ญ์
๋ชจ๋ธ์ ๊ตฌํํ์๋๋ฐ์. ์ด๋ฅผ ์ดํดํ๊ธฐ ์ํด์ InnoDB ์ Locking, Consistent Non-Locking Read, Locking Read ๋ฑ๊ณผ ๊ฐ์ ๊ฐ๋
์ด ์ ํ๋์ด์ผ ํฉ๋๋ค.
CREATE TABLE test (
id BIGINT(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
age BIGINT(20) NOT NULL,
PRIMARY KEY (id)
);
insert into test (id, name, age) values (1, 'quaritch', 25);
insert into test (id, name, age) values (2, 'orca', 26);
insert into test (id, name, age) values (3, 'chan', 26);
insert into test (id, name, age) values (6, 'ori', 27);
insert into test (id, name, age) values (10, 'awesomeo', 26);์ด ๊ธ์์ ์ฌ๋ฌ ์์๋ค์ด ์ฌ์ฉ๋ ์์ ์ ๋๋ค. ๋ชจ๋ ์์๋ ์ ํ ์ด๋ธ์ ๋ฐํ์ผ๋ก ์งํ๋๋ ์ ์ ์ฐธ๊ณ ํ๋ฉฐ ์ฝ์ผ์๋ฉด ์ข ๋ ์ํํ ์ดํด๊ฐ ๊ฐ๋ฅํ ๊ฒ ๊ฐ์ต๋๋ค.
InnoDB Locking
MySQL ์ InnoDB ์์ ๋ค์ํ Locking ๊ธฐ๋ฒ์ ์ฌ์ฉํฉ๋๋ค. ๊ทธ ์ค InnoDB ์ ํธ๋์ญ์
๊ฒฉ๋ฆฌ ์์ค์ ๊ตฌํํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ํ์ ์ธ 3๊ฐ์ง Lock ์ ๋ํด ์ฐ์ ์ดํด๋ณด๊ณ ์ ํฉ๋๋ค.
Record Lock
Record Lock ์ ์ธ๋ฑ์ค ๋ ์ฝ๋์ ์ค์ ๋๋ Lock ์
๋๋ค. ํ
์ด๋ธ์ ์ธ๋ฑ์ค๊ฐ ์ ์๋์ง ์์์ด๋ InnoDB ์์ ์จ๊ฒจ์ง Clustered Index ๋ฅผ ์์ฑํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ํ์ฉํ์ฌ Record Lock ์ ์ ์ฉํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, SELECT name FROM test WHERE id = 1 FOR UPDATE; ๋ผ๋ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฉด id ๊ฐ 1 ์ ํด๋นํ๋ ๋ ์ฝ๋์ Record Lock ์ด ์ค์ ๋๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํธ๋์ญ์
์ด id ๊ฐ 1 ์ธ ๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๋ ์์
์ ์ํํ ์ ์์ต๋๋ค.
์๋๋ ํด๋น ์ํฉ์ ์ฐ์ถํ๊ณ SHOW ENGINE INNODB STATUS ๋ฅผ ํตํด Record Lock ์ด ์ค์ ๋ ๊ฒ์ ํ์ธํ ๋ก๊ทธ์
๋๋ค.
RECORD LOCKS space id 10 page no 4 n bits 72 index PRIMARY of table `transaction_test`.`test`
trx id 3162 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000000c4b; asc K;;
2: len 7; hex 820000008e0110; asc ;;
3: len 8; hex 7175617269746368; asc quaritch;;
4: len 8; hex 8000000000000019; asc ;;Gap Lock
Gap Lock ์ ์ธ๋ฑ์ค ๋ ์ฝ๋ ๊ฐ์ Gap ํน์ ์ฒซ ๋ฒ์งธ ๋๋ ๋ง์ง๋ง ์ธ๋ฑ์ค ๋ ์ฝ๋ ์ /ํ์ Gap ์ ์ค์ ๋๋ Lock ์
๋๋ค. Gap ์์ฒด์ Lock ์ด ์ค์ ๋์๊ธฐ ๋๋ฌธ์ ์ฝ์
ํ๋ ค๋ ๊ณณ์ ๊ฐ ์กด์ฌ ์ฌ๋ถ์ ๊ด๊ณ ์์ด ๋ค๋ฅธ ํธ๋์ญ์
์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, SELECT name FROM test WHERE id >= 1 FOR UPDATE; ๋ผ๋ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ ๋ค๋ฅธ ํธ๋์ญ์
์ด id ๊ฐ 8 ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ๋ ค๊ณ ํ ๊ฒฝ์ฐ ํด๋น id ๊ฐ์ Gap Lock ์ด ์ค์ ๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ ์ฝ์
์์
์ ์ํํ ์ ์์ต๋๋ค.
์๋๋ ํด๋น ์ํฉ์ ์ฐ์ถํ๊ณ Gap Lock ์ด ์ค์ ๋ ๊ฒ์ ํ์ธํ ๊ฒฐ๊ณผ์
๋๋ค.

RECORD LOCKS space id 11 page no 4 n bits 72 index PRIMARY of table `transaction_test`.`test`
trx id 3194 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 8; hex 800000000000000a; asc ;;
1: len 6; hex 000000000c74; asc t;;
2: len 7; hex 82000000ab0110; asc ;;
3: len 4; hex 6f726361; asc orca;;
4: len 8; hex 800000000000001a; asc ;;Next-Key Lock
Next-Key Lock ์ Record Lock ๊ณผ ํด๋น ์ธ๋ฑ์ค ๋ ์ฝ๋ ์์ Gap ์ ๋ํ Gap Lock ์ด ์กฐํฉ๋ Lock ์
๋๋ค. ์์์ ํด๋นํ๋ Next-Key Lock ์ ์๋ ๋ช
์๋ ๊ฒ๊ณผ ๊ฐ์ด ์ ์ฉ๋ฉ๋๋ค.
(negative infinity, 1]
(1, 2]
(2, 3]
(3, 6]
(6, 10]
(10, positive infinity)
๋ง์ง๋ง ๋ฒ์์ ๋ํ Next-Key Lock ์ ์ค์ ์ธ๋ฑ์ค์ ๊ฐ์ฅ ํฐ ๊ฐ๊ณผ ๊ฐ์ฅ ๋์ ๊ฐ์ ๊ฐ๋ ํ์ ์ธ๋ฑ์ค, supremum pseudo-record ๋ฅผ ํตํด Lock ์ ์ค์ ํฉ๋๋ค.

์ค์ ๋ก SELECT โฆ FROM performance_schema.data_locks; ๋ฅผ ํตํด ํ์ธํด๋ณด๋ฉด supremum pseudo-record ๊ฐ LOCK_DATA ๋ก ์กํ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
Consistent Non-Locking Reads
MySQL ์ InnoDB ๋ ๋์์ฑ ์ฑ๋ฅ์ ์ต๋ํํ๊ธฐ ์ํด Multiversion Concurrency Control, MVCC ๋ผ๋ ๊ฐ๋
์ ๋์
ํ์ต๋๋ค. ์ด๋ ๊ฒฉ๋ฆฌ ์์ค์ ๋ฐ๋ผ ์์ดํ์ง๋ง, ํน์ ์์ ์ Snapshot ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก Locking ์ด ํ์ํ์ง ์์ Consistent Read ๋ฅผ ์ ๊ณตํ๋ค๋ ๊ณตํต์ ์ด ์์ต๋๋ค. ์ด๋ฅผ MySQL ์์ Consistent Non-Locking Read ๋ผ๊ณ ํฉ๋๋ค.
REPEATALBE READ๊ฒฉ๋ฆฌ ์์ค์์ ์ต์ดSELECT๋ฌธ์ด ์ํ๋ ์์ ์ ๊ธฐ์ค์ผ๋กSnapshot์ด ์์ฑ๋์ด ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ํด ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์ด๋Undo Log์ ์ ์ฅ๋ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ตฌ์ฑํฉ๋๋ค.READ COMMITTED๊ฒฉ๋ฆฌ ์์ค์์ ๊ฐSELECT๋ฌธ ๋ง๋คSnapshot์ด ์ด๊ธฐํ๋๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ปค๋ฐ์ ์ํด ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๊ฐ์ ์ฝ๊ธฐ ์์ ์ด๋ผ๋ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
Locking Reads
๊ธฐ๋ณธ์ ์ธ SELECT ๋ฌธ์ ํตํด ์กฐํํ ๋ฐ์ดํฐ๋ ๊ธฐ๋ณธ์ ์ผ๋ก Non-Locking Read ์
๋๋ค. ๋๋ฌธ์ ๋ค๋ฅธ ํธ๋์ญ์
์ ์ํด ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. InnoDB ๋ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ ๊ฐ์ง Locking Read ๋ฅผ ์ ๊ณตํฉ๋๋ค.
SELECT โฆ FOR SHARE๋ ์ฝ์ Row ์S-Lock์ ์ค์ ํฉ๋๋ค. ๋ค๋ฅธ ํธ๋์ญ์ ์ด Row ๋ฅผ ์ฝ์ ์ ์์ง๋ง,S-Lock์ ์ค์ ํ ํธ๋์ญ์ ์ด ์ปค๋ฐ๋๊ธฐ ์ ๊น์ง Row ๋ฅผ ์์ ํ ์ ์์ต๋๋ค. ์์ง ์ปค๋ฐ๋์ง ์์ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ํด ํด๋น Row ๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ, ํธ๋์ญ์ ์ด ์ข ๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ ๋ค ๊ฐ์ฅ ์ต์ ํ๋ ๊ฐ์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.SELECT โฆ FOR UPDATE๋ ๊ฒ์์์ ๋ฐ๊ฒฌํ ์ธ๋ฑ์ค ๋ ์ฝ๋์ ๋ํดUPDATE๋ฌธ์ ์คํํ ๊ฒ๊ณผ ๋์ผํ๊ฒ Row ๋ฐ ๊ด๋ จ ์ธ๋ฑ์ค์ Lock ์ ์ค์ ํฉ๋๋ค. ๋ค๋ฅธ ํธ๋์ญ์ ์ ํด๋น Row ๋ฅผUPDATE๋๋SELECT ... FOR SHARE๋ฅผ ์ํํ๋ ๊ฒ์ด ์ ํ๋ฉ๋๋ค.
FOR SHARE ํน์ FOR UPDATE ๋ก ์ค์ ๋ ๋ชจ๋ Lock ์ ํธ๋์ญ์
์ด ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ๋ ๋ ๋ฐํ๋ฉ๋๋ค.
์ฌ๊ธฐ๊น์ง InnoDB ์ Locking, Consistent Non-Locking Read, Locking Read ๋ฑ์ ๋ํด ์์๋ณด์์ต๋๋ค. ์ด์ InnoDB ๊ฐ 4๊ฐ์ง ํธ๋์ญ์
๊ฒฉ๋ฆฌ ์์ค์ ์ด๋ฅผ ํตํด ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
READ UNCOMMITTED
๋จผ์ READ UNCOMMITTED ์
๋๋ค. ํธ๋์ญ์
์ ๋ณ๊ฒฝ ๋ด์ฉ์ด ์ปค๋ฐ์ด๋ ๋กค๋ฐฑ ์ฌ๋ถ์ ๊ด๊ณ ์์ด ๋ค๋ฅธ ํธ๋์ญ์
์ ๋ณด์ด๋ ๊ฐ์ฅ ๋ฎ์ ์์ค์ ๊ฒฉ๋ฆฌ ๋ ๋ฒจ์
๋๋ค. READ UNCOMMITTED ๊ฒฉ๋ฆฌ ์์ค์์ ์ผ๋ฐ์ ์ธ SELECT ๋ฌธ์ Non-Locking Read ๋ก ์ํ๋์ง๋ง MVCC ๋ฅผ ์ฌ์ฉํ์ง ์์ Consistent Read ๋ฅผ ๋ณด์ฅํ์ง์์ต๋๋ค.
Dirty Read
READ UNCOMMITTED ๊ฒฉ๋ฆฌ ์์ค์์ ๋ฐ์ํ ์ ์๋ ์ฝ๊ธฐ ๋ถ์ ํฉ ํ์์
๋๋ค. ๋ค๋ฅธ ํธ๋์ญ์
์ ์ํด ์ํฅ ๋ฐ์ Row ๋ฅผ ์ฝ์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ ํ์์
๋๋ค. ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ์ ๊ด๊ณ ์์ด ๋ณด์ฌ์ง๊ธฐ ๋๋ฌธ์ ๋ถ์ ํํ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ํํ ์ํฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ACID ์ฑ์ง์ ์ค์ํ์ง ๋ชปํ๊ธฐ์ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด InnoDB ์์ MVCC ๋ฅผ ํตํ Consistent Read ๋ฅผ ์ ๊ณตํฉ๋๋ค.
READ COMMITTED
READ COMMITTED ๊ฒฉ๋ฆฌ ์์ค๋ถํฐ MVCC ๊ฐ ์ฌ์ฉ๋์ด Consistent Read ๋ฅผ ์ง์ํ์ง๋ง ๋์ผํ ํธ๋์ญ์
๋ด์์ ๊ฐ SELECT ๋ฌธ์ ์์ฒด์ ์ผ๋ก ์๋ก์ด Snapshot ์ ์์ฑํ๊ธฐ ๋๋ฌธ์ ์์ ํ Consistent Read ๋ฅผ ๋ณด์ฅํ์ง ์์ต๋๋ค.
Locking Read UPDATE DELETE ๋ฌธ์ ๊ฒฝ์ฐ Record Lock ๋ง์ ์ค์ ํ๊ณ Gap Lock ์ ์ค์ ํ์ง ์๊ธฐ์ ๋ค๋ฅธ ํธ๋์ญ์
์์ ์์ ๋กญ๊ฒ Gap ์ ์ ๊ทผํ ์ ์์ต๋๋ค. Gap Lock ์ ์ค์ ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ฒ์ ๊ฒ์๊ณผ ๊ฐ์ ์ฟผ๋ฆฌ์์ Phantom Read ํ์ ์ญ์ ๋ฐ์ํ ์ ์์ต๋๋ค.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
UPDATE test SET name = 'meatsby' WHERE name = 'quaritch';
์ถ๊ฐ์ ์ผ๋ก ์ ๊ทธ๋ผ์ฒ๋ผ UPDATE ์ฟผ๋ฆฌ๋ฅผ ์ํ ํ ํ
์ด๋ธ ์ค์บ ์ READ COMMITTED ๋ ์ค์บ ์ค ๋ง์ฃผ์น๋ ๋ชจ๋ ์ธ๋ฑ์ค ๋ ์ฝ๋์ X-Lock ์ ์ค์ ํ๊ณ WHERE ์ ์ด ์ํ๋ ๋ ์กฐ๊ฑด์ ๋ถํฉํ์ง ์๋ ์ธ๋ฑ์ค ๋ ์ฝ๋์ X-Lock ์ ๋ฐํํ๋ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๋ณ๊ฒฝํ ์ธ๋ฑ์ค ๋ ์ฝ๋๋ฅผ ์ ์ธํ ๋ค๋ฅธ ์ธ๋ฑ์ค ๋ ์ฝ๋์ Lock ์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํธ๋์ญ์ ๊ณผ์ ์ถฉ๋๋ก ์ธํ ๋ฐ๋๋ฝ ๋ฐ์ ํ๋ฅ ์ ํ์ ํ ์ค์๋ค๊ณ MySQL ์ ์๊ฐํฉ๋๋ค.
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
UPDATE test SET name = 'meatsby' WHERE name = 'quaritch';
๋ฐ๋ฉด REPEATABLE READ ์์ ์ค์บ ์ค ๋ง์ฃผ์น๋ ๋ชจ๋ ์ธ๋ฑ์ค ๋ ์ฝ๋์ X-Lock ์ ์ค์ ํ์ฌ ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ๊น์ง Lock ์ ๋ฐํํ์ง ์์ต๋๋ค.
Non-Repeatable Read
READ COMMITTED ๊ฒฉ๋ฆฌ ์์ค๊น์ง ๋ฐ์ํ ์ ์๋ ์ฝ๊ธฐ ๋ถ์ ํฉ ํ์์
๋๋ค. ์์ ์ค๋ช
ํ ๊ฒ ์ฒ๋ผ READ COMMITTED ๊ฒฉ๋ฆฌ ์์ค์์ SELECT ๋ฌธ์ ํญ์ Snapshot ์ ์ด๊ธฐํํ๊ธฐ ๋๋ฌธ์ ํ ํธ๋์ญ์
์์ ๋์ผํ SELECT ๋ฌธ์ ์ํํด๋ ์ผ๊ด๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
REPEATABLE READ
InnoDB ์์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ๊ณตํ๋ ๊ฒฉ๋ฆฌ ๋ ๋ฒจ๋ก, READ COMMITTED ๊ฒฉ๋ฆฌ ์์ค๊ณผ๋ ๋ฌ๋ฆฌ ์ฒ์ ์์ฑ๋ Snapshot ์ ํตํด Consistent Read ๋ฅผ ๋ณด์ฅํฉ๋๋ค. ์ฆ, ๋์ผํ ํธ๋์ญ์
๋ด์ ์ผ๋ฐ์ ์ธ SELECT ๋ฌธ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค.
Locking Read UPDATE DELETE ๋ฌธ์ ๊ฒฝ์ฐ ๊ฒ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ฌ์ฉํ๋ Lock ์ด ๋ฌ๋ผ์ง๋๋ค.
- ๊ณ ์ ํ ๊ฒ์ ์กฐ๊ฑด์ด ์๋ ๊ณ ์ ์ธ๋ฑ์ค์ ๋ํ ์ฟผ๋ฆฌ๋
Record Lock์ด ์ ์ฉ๋ฉ๋๋ค. - ๋ฒ์ ๊ฒ์ ์กฐ๊ฑด๊ณผ ๊ฐ์ ๋ค๋ฅธ ๊ฒ์ ์กฐ๊ฑด์ ๊ฒฝ์ฐ ์ค์บํ ์ธ๋ฑ์ค ๋ฒ์์
Gap Lock๋๋Next-Key Lock์ ์ค์ ํ์ฌ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ํด๋น ๋ฒ์์ ์ ๊ทผํ๋ ๊ฒ์ ์ ํํฉ๋๋ค.
์๋ ์์๋ฅผ ํตํด ์ ๋ ์ํฉ์ ์ข ๋ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
# Session A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM test WHERE id = 6 FOR UPDATE;
ํ์ฌ ์์์์ id ๊ฐ ์ธ๋ฑ์ค๋ก ์์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ณ ์ ํ id ์กฐ๊ฑด์ ํตํด FOR UPDATE ๋ฅผ ์ํํ ๊ฒฝ์ฐ ํด๋นํ๋ ์ธ๋ฑ์ค ๋ ์ฝ๋์๋ง Record Lock ์ด ์ค์ ๋ฉ๋๋ค.
# Session B
INSERT INTO test (id, name, age) VALUES (5, 'test', 26);
๋๋ฌธ์ ๋ค๋ฅธ ํธ๋์ญ์ ์ด Gap ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ ๋ ์๋ฌด ์ ํ ์์ด ์ ์์ ์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ฝ์ ๋ฉ๋๋ค.
# Session A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM test WHERE age = 25 FOR UPDATE;
๋ฐ๋ฉด age ์ ๊ฐ์ด ํ์ฌ ํ
์ด๋ธ ์ํ์์ ๊ณ ์ ํ์ง๋ง ์ธ๋ฑ์ค๊ฐ ์๋ ์กฐ๊ฑด์ ํตํด FOR UPDATE ๋ฅผ ์ํํ ๊ฒฝ์ฐ ํ ํ
์ด๋ธ ์ค์บ์ ํตํด ํด๋น ์ธ๋ฑ์ค ๋ ์ฝ๋๋ฅผ ํ์ํ๊ธฐ ๋๋ฌธ์ ๊ทธ ๊ณผ์ ์์ ๋ง์ฃผ์น ๋ชจ๋ ์ธ๋ฑ์ค ๋ ์ฝ๋์ X-Lock ์ด ์ ์ฉ๋ฉ๋๋ค.
# Session B
INSERT INTO test (id, name, age) VALUES (5, 'test', 26);
์ด ์ํ์์ ๋ค๋ฅธ ํธ๋์ญ์
์ด Gap ์ id ๊ฐ 5 ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ๋ ค๊ณ ํ ๊ฒฝ์ฐ id ๊ฐ 6 ์ธ ์ธ๋ฑ์ค ๋ ์ฝ๋์ Gap Lock ์ผ๋ก ์ธํด ๋ฐ์ดํฐ ์ฝ์
์ด ์ ํ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด InnoDB ์์ REPEATABLE READ ์์ค์์๋ Phantom Read ํ์์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
Phantom Read
A : START TRANSACTION;
A : SELECT * FROM test; # ์ต์ด Snapshot ์์ฑ
B : INSERT INTO test (id, name, age) VALUES (5, 'test', 26); # Lock ์ด ๊ฑธ๋ ค์์ง ์๊ธฐ ๋๋ฌธ์ Gap ์ ๋ฐ์ดํฐ ์ฝ์
๊ฐ๋ฅ
A : SELECT * FROM test; # ์ต์ด Snapshot ์ ๊ทธ๋๋ก ์ฌ์ฉ
A : UPDATE test SET name = 'twenty-six' WHERE age = 26; # Locking Read ๋ฅผ ํตํด ์๋กญ๊ฒ ์ฝ์ ํ UPDATE
A : SELECT * FROM test; # Snapshot ์ด ์ด๊ธฐํ๋์ด Phantom Read ๋ฐ์์ฌ์ ํ ์ด๋ฐ ๊ตฌ์กฐ์๋ ๋ถ๊ตฌํ๊ณ REPEATABLE READ ์์ Phantom Read ๊ฐ ๋ฐ์ํ ์ ์๋ ์ํฉ์ด ์์ต๋๋ค.
์ ์ํฉ์ฒ๋ผ ๋ค๋ฅธ ํธ๋์ญ์
์ด ์ถ๊ฐํ ๋ ์ฝ๋์ UPDATE ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฒ ๋ ๊ฒฝ์ฐ, ์ฒซ SELECT ์ฟผ๋ฆฌ๋ก ์์ฑ๋ Snapshot ์๋ ์กด์ฌํ์ง ์์ง๋ง ์ค์ ๋์คํฌ์๋ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ํด๋น ๋ ์ฝ๋๊ฐ ์ํฅ์ ๋ฐ์ ์ดํ SELECT ์ฟผ๋ฆฌ๋ฅผ ์ํํ ๋ Snapshot ์ด ์ด๊ธฐํ๋๋ ์์ ์ ํด๋น ํ์์ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
์ฆ, Consistent Non-Locking Read ์ Locking Read ์ ์กฐํฉ ๋๋ฌธ์ ๋ฐ์ํ ์ ์๋ ํ์์
๋๋ค.
์์ ์ค๋ช
ํ ๊ฒ ์ฒ๋ผ ์ผ๋ฐ์ ์ธ SELECT ๋ฌธ์ Non-Locking Read ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ธฐ ๋๋ฌธ์ UPDATE ๋ฅผ ์ํ SELECT ๋ SELECT โฆ FOR UPDATE ์ ๊ฐ์ด Locking Read ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ ํฉํฉ๋๋ค.
๋ฐ๋ผ์, ์ ์์์์ ์ฐ์ถํ๋ ์ํฉ ์์ฒด๊ฐ ๋ถ์ ์ ํ๋ค๊ณ ์๊ฐํ์ง๋ง, ์ฌ์ ํ ๋ฐ์ํ ์ ์๋ ํน์ ์ํฉ์ด ์กด์ฌํ๋ค๋ ์ฌ์ค์ ์๊ณ ์๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
SERIALIZABLE
๋ง์ง๋ง SERIALIZABLE ์ ๊ฐ์ฅ ๋์ ์์ค์ ๊ฒฉ๋ฆฌ ๋ ๋ฒจ์
๋๋ค. ์ด๋ฆ์ฒ๋ผ ์ง๋ ฌํ๋ ๋ฐฉ์์ฒ๋ผ ์๋ํด์ผํฉ๋๋ค. InnoDB ์์ ์ด๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ์ผ๋ฐ์ ์ธ SELECT ๋ฌธ์ ๋ชจ๋ SELECT โฆ FOR SHARE ๋ฌธ์ผ๋ก ๋ณํํ์ฌ S-Lock ์ ํตํ Locking Read ๋ฅผ ์ํํ๊ฒ๋ ํฉ๋๋ค.
๊ธ ์ด๋ฐ๋ถ ์ค๋ช
๋์ด์๋ฏ์ด S-Lock ์ ๋ค๋ฅธ ํธ๋์ญ์
๋ ๋
๋ฆฝ์ ์ผ๋ก ์ค์ ์ด ๊ฐ๋ฅํ์ฌ S-Lock ์ด ์ค์ ๋ ๋ ์ฝ๋๋ฅผ ์ฝ์ ์ ์์ง๋ง ์ต์ด๋ก S-Lock ์ ์ค์ ํ ํธ๋์ญ์
์ด ์ข
๋ฃ๋๊ธฐ ์ ๊น์ง ๋ณ๊ฒฝ์ ๊ฐํ ์ ์์ต๋๋ค.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM test;
์ ๊ทธ๋ฆผ์ฒ๋ผ ๋จ์ํ SELECT ๋ฌธ์ ์ํํด๋ ๋ชจ๋ ๋ ์ฝ๋์ S-Lock ์ด ์ค์ ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋ง๋ฌด๋ฆฌ
์ฌ๊ธฐ๊น์ง MySQL ์ InnoDB ๊ฐ 4๊ฐ์ง ๊ฒฉ๋ฆฌ ์์ค์ ๊ตฌํํ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค. ๊ฒฉ๋ฆฌ ์์ค์ ๋์์ฑ๊ณผ ๊ฒฉ๋ฆฌ์ฑ์ Trade-Off ์ธ ๋งํผ ์์ธํ ์๊ณ ์ฌ์ฉํ๋ฉด ๋ ์ข์ ํจ๊ณผ๋ฅผ ๋ํ๋ผ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
MySQL ์ ๋ค๋ฅธ DBMS ๋ฒค๋๋ค๊ณผ๋ ๋ฌ๋ฆฌ InnoDB ๋ฅผ ํตํด REPEATABLE READ ์์๋ ์ถฉ๋ถํ ๊ฒฉ๋ฆฌ์ฑ์ ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค. ํ์ง๋ง ์ฌ๋ฌ๊ฐ์ง Locking ๊ธฐ๋ฒ์ ํ์ฉํ์ฌ ๊ฒฉ๋ฆฌ ์์ค์ ๊ตฌํํ๊ธฐ ๋๋ฌธ์ Locking ์ผ๋ก ์ธํด ๋ฐ์ํ ์ ์๋ ์ฌ๋ฌ ๋ฌธ์ ์ ์ญ์ ์ถฉ๋ถํ ์ดํดํ๋ ๊ฒ์ด ์ค์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.