์ด์ ํฌ์คํ ์์๋ MVCC๋ ๋ฌด์์ธ์ง, MVCC๊ฐ ์ ์ฉ๋ RDBMS์์ isolation level๋ง๋ค ์ด๋ป๊ฒ ๋์ํ๋ ์ง์ ๋ํด์ ์ดํด๋ณด์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด์ ํฌ์คํ ์์๋ ํ ํธ๋์ญ์ ์์ ๊ฐ์ ๋ฐ์ดํฐ์ ๋ํ read๋ฅผ ๋ ๋ฒ ํ์ ๋ read committed, repeatable read level์์ MySQL, PostgreSQL์ด ์ด๋ป๊ฒ ๋์ํ๋ ์ง๋ฅผ ์ดํด๋ณด์์ต๋๋ค.
์ค๋์ MVCC๊ฐ ์ ์ฉ๋ MySQL, PostgreSQL์์ ํธ๋์ญ์ ์ด ๊ฐ์ ๋ฐ์ดํฐ์ write๋ฅผ ํ๋ ๋์์์ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ๊ฐ๊ฐ isolation level๋ง๋ค ๊ทธ๋ฆฌ๊ณ RDBMS๋ง๋ค ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ์์๋ณด๊ฒ ์ต๋๋ค.
DB ์๋ฆฌ์ฆ ํฌ์คํ ์์ lost update์ ๋ํด์ ์ดํด๋ณธ ์ ์ด ์์ต๋๋ค.
lost update๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ ์๋ก ๋ค๋ฅธ ๋ ํธ๋์ญ์ ์ด ๊ฐ์ ๋ฐ์ดํฐ์ ๋ํด write ์์ ์ ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ์ต๋๋ค. ํ ํธ๋์ญ์ ์ด updateํ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ผ์ง๋ ๊ฒ์ ๋๋ค.
x=50, y=10
tx1. x๊ฐ y์ 40์ ์ด์ฒดํ๋ค. read committed
tx2. x์ 30์ ์ ๊ธํ๋ค. read commited
read(tx1,x) - write(tx1,x=10) - read(tx2,x) - write(tx2,x=80)(block) - read(tx1,y) - write(tx1,y=50) - commit1 - write(tx2,x=80) - commit2
tx1์์ x์ ๊ฐ์ ์ฝ์ต๋๋ค. commit๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ผ ํ๋๊น x=50์ ์ฝ์ด์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ 40์ ๋นผ์ผํ๋๊น x=10 write ์์ ์ ํฉ๋๋ค. ๋น์ฐํ ์ํํ๊ธฐ ์ ์ write-lock์ ํ๋ํฉ๋๋ค.
tx1์์ x=10 write ์์ ์ ๋ฐ๋ก ๋์คํฌ์ ์ ์ฉ๋๋ ๊ฒ์ด ์๋ snapshot์ผ๋ก ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ด ์ ์ฅ๋ฉ๋๋ค.
tx2์์ x์ ๊ฐ์ ์ฝ์ต๋๋ค. commit๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ผ ํ๋๊น x=50์ ์ฝ์ด์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ 30์ ๋ํด์ผํ๋๊น x=80 write ์์ ์ ํ๋ ค๊ณ ํ์ง๋ง, ์ด๋ฏธ tx1์ด x์ ๋ํด write-lock์ ์ ์ ํ๊ณ ์๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ write-lock์ ํ๋ํ์ง ๋ชปํ๊ณ block ๋ฉ๋๋ค.
tx1์ ๊ณ์ ์งํํด์ y=10์ ์ฝ๊ณ y์ 40์ ๋ํด y=50 write๋ฅผ ํ๊ธฐ ์ํด์ y์ ๋ํ write-lock์ ํ๋ํ๊ณ write๋ฅผ ์งํํฉ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก snapshot์ผ๋ก ์ ์ฅํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ tx1์ commit์ ํฉ๋๋ค.
์ด ํ์์ผ tx2๋ x์ ๋ํ write-lock์ ํ๋ํ์ฌ x=80์ snapshot์ผ๋ก ์ ์ฅํ๊ณ commitํฉ๋๋ค.
๊ทธ๋ผ ๊ฒฐ๊ณผ์ ์ผ๋ก tx1์ด ์ ์ฅํ x=10, y=50์ด ์๋ x=80, y=50์ด ๋์คํฌ์ ์ ์ฅ๋ฉ๋๋ค.
tx1์ด ์งํํ update๊ฐ ์ฌ๋ผ์ง lost update๊ฐ ๋ฐ์ํ์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์์๊น์?
tx2์ isolation level์ repeatable read๋ก ๋ณ๊ฒฝํฉ๋๋ค.
์์ schedule๊ณผ ๋๊ฐ์ต๋๋ค. ํ์ง๋ง tx1์ด ๋จผ์ commitํ๊ธฐ ๋๋ฌธ์ tx2๊ฐ write(x=80)์ ํ๋ ค๊ณ ํ๋ฉด ์คํจํ๊ณ tx2๋ rollback๋ฉ๋๋ค.
์๋ํ๋ฉด PostgreSQL์์๋ ๊ฐ์ ๋ฐ์ดํฐ์ ๋ํด์ ๋จผ์ updateํ ํธ๋์ญ์ ์ด commit ๋๋ฉด ๋์ค ํธ๋์ญ์ ์ rollbackํ๋ ๊ท์น์ด ์์ต๋๋ค. ์ด๋ฐ ํน์ง์ first-updater-win์ด๋ผ๊ณ ํฉ๋๋ค.
๋จผ์ updateํ ํธ๋์ญ์ ์ด rollbackํ๋ ๊ฒฝ์ฐ๋ ์๊ด ์์ต๋๋ค.
๊ทธ๋์ ๊ฒฐ๊ตญ tx1๋ง ์ฑ๊ณตํ๊ธฐ ๋๋ฌธ์ x=10, y=50์ด ๋์คํฌ์ ์ ์ฉ๋ฉ๋๋ค.
๐จ๊ทธ๋ผ tx1์ read committed๋ก ๋ฌ๋ ๊ด์ฐฎ์๊น์?
๊ฒฐ๋ก ๋ง ๋งํ๋ฉด ์๋๋๋ค. tx1๋ repeatable read๋ก ๋ฐ๊ฟ์ค์ผ ํฉ๋๋ค.
tx2๊ฐ ๋จผ์ ์์ํ๋ schedule์ ๊ฐ์ ํด๋ด ์๋ค. ํ์ฌ tx1์ read committed์ ๋๋ค.
read(tx2,x) - read(tx1,x) - write(tx2,x=80) - write(tx1,x=10)(block) - commit2 - write(tx1,x=10) - read(tx1,y) - write(tx1,y=50) - commit1
read committed์์๋ ๋จผ์ updateํ ํธ๋์ญ์ ์ด commit์ ๋์ค ํธ๋์ญ์ ์ rollbackํ๋ค๋ ๊ท์น์ด ์ ์ฉ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋๊ฐ์ด lost update๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ฆ, PostgreSQL์์ lost update๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๊ด๋ จ์๋ ํธ๋์ญ์ ์ isolation level์ ๋ชจ๋ repeatable read๋ก ๋ฐ๊ฟ์ค์ผ ํฉ๋๋ค.
MySQL์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก MVCC๊ฐ ์ ์ฉ๋์๋๋ผ๋ read committed level์ผ ๋ lost update๊ฐ ๋ฐ์ํฉ๋๋ค.
MySQL๋ PostgreSQL์ฒ๋ผ ๋ ํธ๋์ญ์ ์ ๋ชจ๋ repeatable read๋ก ๋ณ๊ฒฝํ๋ฉด ํด๊ฒฐ๋ ๊น์?
์ํ๊น๊ฒ๋ MySQL์์๋ repeatable read์ first-updater-win์ด๋ผ๋ ๊ฐ๋ ์ด ์์ต๋๋ค.
๋ฐ๋ผ์ repeatable read๋ก ๋ณ๊ฒฝํด๋ ํธ๋์ญ์ ์ ์คํจํ์ง ์๊ณ ์ญ์ฑ ์งํํด lost update๊ฐ ๊ฒฐ๊ตญ ๋ฐ์ํฉ๋๋ค.
์ฆ, MySQL์ MVCC๋ lost update๋ฅผ repeatable read๋ก ๋ฐ๊พธ๋ ๊ฒ๋ง์ผ๋ก๋ lost update๋ฅผ ํด๊ฒฐํ ์๊ฐ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
๋ ํธ๋์ญ์ ์ ์ง๊ธ repeatable read level์ ๋๋ค.
read(tx2,x) - read(tx1,x)(block) - write(tx2,x=80) - commit2 - read(tx1,x) - write(tx1,x=10) - read(tx1,y) - write(tx1,y=50) - commit1
MySQL์์๋ read ์์ ์ ํ ๋ lock์ ์ทจ๋ํ ์ ์๋๋ก ํด์ผํฉ๋๋ค. ์ด๋ฅผ MySQL์์๋ locking read๋ผ๊ณ ํฉ๋๋ค.
๊ทธ๋์ tx1, tx2 ๋ชจ๋ x์ ๋ํ read ์์ ์ ํ ๋ write-lock์ ์ทจ๋ํด์ผ ํฉ๋๋ค.
read ์์
์ ํ ๋ wirte-lock์ ์ทจ๋ํ๊ธฐ ์ํด์๋ select SQL๋ฌธ์ FOR UPDATE
๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด read๋ฅผ ํ๋๋ผ๋ ํด๋น ๋ฐ์ดํฐ์ ๋ํ write-lock์ ์ทจ๋ํ ์ ์์ต๋๋ค.
๊ทธ๋ผ schedule์ ์ดํด๋ณด๋ฉด tx2๊ฐ x๋ฅผ ์ฝ๊ธฐ ์ํด write-lock์ ์ทจ๋ํ๊ณ read๋ฅผ ์งํํ์ต๋๋ค.
tx1๋ x๋ฅผ ์ฝ๊ธฐ ์ํด write-lock์ ์ทจ๋ํ๋ ค ํ์ง๋ง ์ด๋ฏธ tx2๊ฐ ์ ์ ํ๊ณ ์์ด์ ์ทจ๋ํ ์ ์๊ณ ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
tx2๋ ๊ณ์ ์งํํด์ x=80์ผ๋ก ์ ๋ฐ์ดํธํ๊ณ commitํฉ๋๋ค.
tx1์ ์ด์ lock์ ํ๋ํ ์ ์๊ณ read ์์ ์ ์งํํฉ๋๋ค. ์ง๊ธ tx1์ repeatable read level์ด๋ผ์ ํธ๋์ญ์ ์ด ์์ํ ์์ ์์ ๊ฐ์ฅ ์ต๊ทผ์ commit๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ต๋๋ค. ๋ฐ๋ผ์ x=50์ ์ฝ์ด์ผ ์ ์์ ๋๋ค.
ํ์ง๋ง x=80์ ์ฝ๊ฒ ๋ฉ๋๋ค. ๊ทธ ์ด์ ๋ locking read๋ ๊ฐ์ฅ ์ต๊ทผ์ commit๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ ๋๋ฌธ์ read ์์ ์์ ๊ฐ์ ์ต๊ทผ์ commit๋ ๋ฐ์ดํฐ๋ tx2๊ฐ commitํ ๋ฐ์ดํฐ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
MVCC๊ฐ ์ ์ฉ๋ MySQL์ locking read๋ isolation level๊ณผ ์๊ด ์์ด read๋ฅผ ์ด๋ ๊ฒ ํ๋ค๋ ๊ฒ์ ๊ผญ ๊ธฐ์ตํด์ผ ํฉ๋๋ค.
๊ทธ ํ์ tx1๊ฐ x์ 40์ ๋นผ์ผํ๋ฏ๋ก x=50 write ์์ ์ ํ๊ณ read(y) ์์ ์ ํ๋๋ฐ ์ด ๋๋ locking read๋ก ์ฝ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค๋ฅธ ํธ๋์ญ์ ์ด ํด๋น ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ write ์์ ์ ํ ์๋ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด์ฐ๋๋ ์ด๋ ๊ฒ ์งํ์ด ๋๋ฉด ๊ฒฐ๊ตญ x=40, y=50์ผ๋ก ์ ์์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋์คํฌ์ ์ ์ฅํ ์ ์์ต๋๋ค.
๊ทธ๋์ ๊ฒฐ๋ก ์ ์ผ๋ก MySQL์์๋ repeatable read๋ฅผ ์ฐ๋ ๊ฒ๋ง์ผ๋ก๋ ํด๊ฒฐ๋์ง ์๊ณ locking read๋ฅผ ์ฌ์ฉํด์ผ lost update๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ๋ฌผ๋ก serializable level์ ์ฌ์ฉํ๋ค๋ฉด repeatable level ๋ง์ผ๋ก๋ ๊ฐ๋ฅํ ๊ฒ์ ๋๋ค.
PostgreSQL์์ ์๋ก ๋ค๋ฅธ ๋ ํธ๋์ญ์ ์ค ํ๋์ ํธ๋์ญ์ ๋ง repeatable read๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ์๋ ๊ด๋ จ์๋ ํธ๋์ญ์ ๋ repeatable read๋ฅผ ์ฌ์ฉํด์ผ lost update๋ฅผ ๋ฐฉ์งํ ์ ์๋ค๊ณ ํ์ต๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก MySQL์์๋ ๊ด๋ จ์๋ ๋ค๋ฅธ ํธ๋์ญ์ ์์๋ ๊ฐ์ ๋ฐ์ดํฐ์ ๋ํด locking read(write-lock)์ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
MySQL์ locking read๋ ์ข ๋ฅ๊ฐ ์์ต๋๋ค.
select ... for update;
select ... for share;
for update์ ๊ฒฝ์ฐ์๋ exclusive lock์ ํ๋ํ๊ฒ ๋๋ ๊ฒ์ด๊ณ , for share์ ๊ฒฝ์ฐ์๋ shared lock์ ํ๋ํ๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
์ด๋ฐ for update, for share
๊ฐ์ ๋ฌธ๋ฒ์ MySQL ๋ง๊ณ PostgreSQL์์๋ ์กด์ฌํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋์๋ฐฉ์์ด ์กฐ๊ธ ๋ค๋ฆ
๋๋ค.
x=10, y=10
tx1. x์ y๋ฅผ ๋ํด์ x์ ์ด๋ค.
tx2. x์ y๋ฅผ ๋ํด์ y์ ์ด๋ค.
์ด ๋ ๊ฐ์ ํธ๋์ญ์ ์ด ๊ฐ๊ฐ ๋์ํ๋๋ก ์ํ๋๋ฉด ์ ์์ ์ธ ๊ฒฐ๊ณผ๋ x=20,y=30 ํน์ x=30,y=20์ด ๋์ด์ผ ํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ MVCC์์ repeatable read level๋ก ํธ๋์ญ์ ์ด ๋์ํ๊ฒ ๋๋ฉด ์ด์ํ ํ์์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ schedule๋ก ์งํ๋๋ค๊ณ ์๊ฐํด๋ด ์๋ค
read(tx1,x) - read(tx2,x) - read(tx1,y) - read(tx2,y) - write(tx1,x=20) - write(tx2,y=20) - commit1 - commit2
์์๋๋ก ๋ฐ๋ผ๊ฐ๋ณด๋ฉด ๊ฒฐ๊ณผ๊ฐ x=20, y=20์ด ๋์คํฌ์ ์ ์ฅ๋ฉ๋๋ค. ์ ์์ ์ธ ๊ฒฐ๊ณผ๊ฐ ์๋ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ฉด์ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ด ๊นจ์ก์ต๋๋ค.
์ด๋ ๊ฒ ์๋ก ๊ด๋ จ์๋ ๋ฐ์ดํฐ์ ๋ํด ์ฐ๊ธฐ ์์ ์ ํ๊ณ ๋์ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ด ๊นจ์ง๋ ํ์์ write skew๋ผ๊ณ ํ๋ค๊ณ ์ด์ ํฌ์คํ ์์ ์ดํด๋ณด์์ต๋๋ค.
์๊น lost update๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ฒ๋ผ locking read๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
read(tx1,x) - read(tx2,x)(block) - read(tx1,y) - write(tx1,x=20) - commit1 - read(tx2,x) - read(tx2,y) - write(tx2,y=20) - commit2
tx1์์ x๋ฅผ ์ฝ๊ธฐ ์ํด locking read๋ก write-lock์ ์ทจ๋ํ ํ ์ฝ์ต๋๋ค. tx2์์๋ x์ ๋ํด์ readํ๋ ค๊ณ ํ๋ฉด lock์ ํ๋ํ์ง ๋ชปํด์ ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ๊ทธ๋์ tx2๋ block๋ฉ๋๋ค.
tx1์ ๋ง์ ์งํํฉ๋๋ค. tx1์ด y๋ฅผ ์ฝ์ผ๋ ค๊ณ ํ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก locking read๋ก y์ ๋ํ write-lock์ ์ทจ๋ํ๊ณ read ์์ ์ ํฉ๋๋ค.
tx1์ด x=20 write ์์ ์ ํ๊ณ commit์ ์งํํฉ๋๋ค.
tx2๋ ์ด์ x์ ๋ํ write-lock์ ์ฅ ์ ์๊ฒ ๋๊ณ read(x)๋ฅผ ํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ ์์์ ๋งํ๋ฏ์ด repeatable read์์ locking read๋ก ๋์ํ๋ ๊ฒฝ์ฐ read ์์ ์์ ๊ฐ์ฅ ์ต๊ทผ์ commit๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ ๋๋ฌธ์ x=10์ด ์๋ x=20์ ์ฝ์ด์ต๋๋ค.
tx2๊ฐ y๋ฅผ ์ฝ์ ๋๋ locking read๋ฅผ ์งํํ๊ณ y=20 write ์์ ๊น์ง ๋ง์น ํ ํธ๋์ญ์ ์ด ์ข ๋ฃ๋ฉ๋๋ค.
x=20,y=30์ผ๋ก ์ ์์ ์ธ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
๊ทธ๋์ MySQL์์ write skew๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด lost update์ฒ๋ผ locking read๋ฅผ ์ฌ์ฉํ๋ฉด write-skew๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
PostgreSQL์์๋ for update, for share
๋ฌธ๋ฒ์ด ์กด์ฌํ๋ค๊ณ ํ์ต๋๋ค. ๊ทธ๋์ PostgreSQL์๋ ์ด ๋ฐฉ๋ฒ์ ์ ์ฉํ ์ ์๋๋ฐ MySQL๊ณผ ๋์๋ฐฉ์์ด ์ข ๋ค๋ฆ
๋๋ค.
read(tx1,x) - read(tx2,x)(block) - read(tx1,y) - write(tx1,x=20) - commit1 - read(tx2,x) - read(tx2,y) - write(tx2,y=20) - commit2
๋ง์ฐฌ๊ฐ์ง๋ก ๋๊ฐ์ schedule์ ๋๋ค.
PostgreSQL์์๋ for update
๋ฅผ ํตํด์ ์ฝ๊ธฐ ์์
์ ํ๊ธฐ ์ํด write-lock์ ํ๋ํ ์ ์์ต๋๋ค.
PostgreSQL์์๋ repeatable read leve์ผ ๋ ๋จผ์ updateํ ํธ๋์ญ์ ์ด commit ๋๋ฉด ๋์ค tx๋ rollback ๋๋ค๊ณ ํ์ต๋๋ค.(first-updater-win)
๋ฐ๋ผ์ commit1 ์ดํ tx2๊ฐ read(x)ํ๋ ์์ ์ ์คํจํ๊ณ tx2๋ rollbackํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋์ ๊ฒฐ๊ตญ ์ต์ข ๊ฒฐ๊ณผ๋ x=20,y=10์ผ๋ก ๋จ๊ฒ ๋ฉ๋๋ค.
์ด์ฐ๋๋ tx2๊ฐ ๋์ํ์ง ์์๊ธฐ ๋๋ฌธ์ ์ ๊ฒฐ๊ณผ๋ ์ ์์ ์ธ ๊ฒฐ๊ณผ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์คํจํ tx2๋ ๋์ค์ ๋ค์ ์คํ์ ํด์ฃผ๋๊ฐ ํด์ผํฉ๋๋ค.
for update, for share
๋ ๋ค first-updater-win ๊ท์น์ด repeatable read์์ ์ ์ฉ์ด ๋ฉ๋๋ค.
์ด๋ฒ์ for share๋ฅผ ์ฌ์ฉํด์ read-lock์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋ํด์ ๊ฐ๋จํ ์ดํด๋ด ์๋ค.
write(tx1,x=20) - read(tx2,x)(block) - ... - commit1 - read(tx2,x)(abort) - rollback
tx1์ด x์ ๋ํด wrtie ์์ ์ ํ ์ดํ์ tx2๊ฐ x์ ๋ํด read ์์ ์ ์ํด read-lock์ ํ๋ํ๋ ค๊ณ ํ๋ฉด tx2๋ block ๋ฉ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก MVCC๋ write-write operation์ ๋ํด์๋ง block์ด ์ด๋ฃจ์ด์ง์ง๋ง, read-lock์ ์ฌ์ฉํ๊ณ ์ถ์ ๊ฒฝ์ฐ๋ ์๊ธฐ๋๋ฐ ์ด ๋ for share
๋ฌธ๋ฒ์ผ๋ก read-lock์ ์ฌ์ฉํ๋ ค๊ณ ํ๋ฉด read-read๋ง ํ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๋์ํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋์ tx2๋ block๋๊ณ tx1์ด ์งํ๋๋ค commit์ด ์ด๋ฃจ์ด์ง๋ฉด, tx2๋ x์ ๋ํ read-lock์ ์ฅ๊ณ read(x)๋ฅผ ํ ์ ์๋๋ฐ first-updater-win ๊ท์น ๋๋ฌธ์ read ์์ ์ ์คํจํ๊ณ tx2๋ rollbackํ๊ฒ ๋ฉ๋๋ค.
select...for update;
select...for share;
์ ๋ฌธ๋ฒ์ผ๋ก repeatable read level์ผ ๋๋ write skewํ์์ ํด๊ฒฐํ ์ ์์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ MySQL, PostgreSQL์์ ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง ๋์ ๋์ ๋ฐฉ์์ ์ฝ๊ฐ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
tx1์ด serializable๋ก ๋์ํ ๋ ๊ฒฐ๊ณผ๋ repeatable read์ผ ๋์ ๋์ผํฉ๋๋ค. ํ์ง๋ง serializable level์ผ ๋ MySQL๊ณผ PostgreSQL ๋์์์ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
๐จMySQL
MVCC๋ก ๋์ํ๊ธฐ ๋ณด๋ค๋ lock์ผ๋ก ๋์ํฉ๋๋ค.
repeatable read์ ์ ์ฌํ๊ฒ ๋์ํ์ง๋ง, serializable level ํธ๋์ญ์
์ ๋ชจ๋ ํ๋ฒํ select ๋ฌธ์ ์๋ฌต์ ์ผ๋ก select ... for share
์ฒ๋ผ ๋์ํฉ๋๋ค.
๊ฐ๋ฐ์๊ฐ ํ๋ฒํ select๋ฌธ์ ์ผ๋ค ํ๋๋ผ๋ DBMS๊ฐ ์์์ for share
๋ฅผ ๋ถ์ฌ์ฃผ๋ ์๋ฏธ๋ค.
exclusive lock์ด ์๋ shared lock์ด๊ธฐ ๋๋ฌธ์ deadlock์ด ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋ ๋์ต๋๋ค.
๐จPostgreSQL
Serializable Snapshot Isolation ๊ธฐ๋ฒ์ด ์ ์ฉ๋ MVCC๋ก ๋์ํฉ๋๋ค. MVCC๋ก ๋์ํ๋ฉด์๋ ๋ชจ๋ ์ด์ํ์์ ๋ง์์ฃผ๋ isolation ๊ธฐ๋ฒ์ด๋ผ๊ณ ํฉ๋๋ค.
์ด ๋ถ๋ถ์ ์ถ๊ฐ์ ์ผ๋ก ๊ณต๋ถ๊ฐ ํ์ํ ๊ฒ ๊ฐ์ต๋๋ค.