๐ฑ ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค(Transaction Isolation Level)
ํธ๋์ญ์ ์ ๊ฒฉ๋ฆฌ ์์ค(Isolation Level)์ด๋ ์ฌ๋ฌ ํธ๋์ญ์ ์ด ๋์์ ์ฒ๋ฆฌ๋ ๋, ํน์ ํธ๋์ญ์ ์ด ๋ค๋ฅธ ํธ๋์ญ์ ์์ ๋ณ๊ฒฝํ๊ฑฐ๋ ์กฐํํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณผ ์ ์๊ฒ ํ์ฉํ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ๊ฒ์ด๋ค.
ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค์ ๊ฒฉ๋ฆฌ(๊ณ ๋ฆฝ) ์์ค์ด ๋ฎ์ ์์๋๋ก READ UNCOMMITED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE๊ฐ ์กด์ฌํ๋ค.
- READ UNCOMMITED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
์ฐธ๊ณ ๋ก ์๋์ ์์ ๋ค์ ๋ชจ๋ ์๋ ์ปค๋ฐ(AUTO COMMIT)์ด false์ธ ์ํ์์๋ง ๋ฐ์ํ๋ค.
1๏ธโฃ READ UNCOMMITED (Level 0)
READ UNCOMMITTED๋ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ปค๋ฐํ์ง ์์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๋ ๊ฒฉ๋ฆฌ ์์ค์ด๋ค.
READ UNCOMMITTED์์๋ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์์ ์ด ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ๋์ง ์์๋ ์ฆ์ ๋ณด์ด๊ฒ ๋๋ค.
1. ์๊ธ ์์ ํธ๋์ญ์ ์์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ 250๋ง์์์ 300๋ง์์ผ๋ก ์์ ํ๋ ํธ๋์ญ์ ์ด ์์๋๋ค.
3. ์๊ธ ์กฐํ ํธ๋์ญ์ ์์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ ์กฐํํ๋ค.
4. READ UNCOMMITTED์์๋ ์ปค๋ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ 300๋ง์์ผ๋ก ์กฐํํ๋ค.
5. ์๊ธ ์์ ํธ๋์ญ์ ์์ ์ด๋ ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํด ROLLBACK ๋๋ค.
6. ์กฐ๊ธ ๋ค์ ๋ค์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ ์กฐํ๋ฅผ ํด๋ณด๋ 250๋ง์์ผ๋ก ์กฐํ๋๋ค.
์๊ฐ | ์๊ธ ์์ ํธ๋์ญ์ | ์๊ธ ์กฐํ ํธ๋์ญ์ |
09:37:00 | ํธ๋์ญ์ BEGIN | |
09:37:01 | ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ 300๋ง์์ผ๋ก UPDATE | |
09:37:02 | ํธ๋์ญ์ BEGIN | |
09:37:03 | ๊น๊ฐ๋ ์ฌ์ ์๊ธ ์กฐํ: 300๋ง์ | |
09:37:04 | ํธ๋์ญ์ COMMIT | |
09:37:05 | ํธ๋์ญ์ ROLLBACK |
DB์์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ด 300๋ง์์ด ๋ ์ ์ด ์๋๋ฐ 09์ 37๋ถ 3์ด์ ์๊ธ ์กฐํ ํธ๋์ญ์ ์ ์ปค๋ฐ๋์ง ์์ ๋ฐ์ดํฐ์ธ 300๋ง์์ ์ฝ์ด๊ฐ๋ค.
→ dirty read ๋ฐ์
์ปค๋ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ ์๊ธฐ๋ ๋ฌธ์ ์ ๊ฐ์ด dirty readํ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด DB๋ฅผ UPDATE ํ๋ค๋ฉด ๋ ํฐ ๋ฌธ์ ๊ฐ ์ผ์ด๋ ๊ฒ์ด๋ค.
์ด์ฒ๋ผ READ UNCOMMITTED ๊ฒฉ๋ฆฌ์์ค์ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ RDBMS ํ์ค์์๋ ๊ฒฉ๋ฆฌ ์์ค์ผ๋ก ์ธ์ ๋์ง ์๋๋ค.
2๏ธโฃ READ COMMITTED (Level 1)
READ COMMITTED๋ ์ปค๋ฐ๋ ๋ฐ์ดํฐ๋ง ์กฐํํ ์ ์๋ค.
์ด ๊ฒฉ๋ฆฌ ์์ค์ Oracle, PostgreSQL ๋ฑ ๋ง์ RDBMS์ default ๊ฒฉ๋ฆฌ ์์ค์ด๋ค.
READ COMMITTED์ READ UNCOMMITTED ๊ฒฉ๋ฆฌ์์ค์์ ๋ฐ์ํ๋ dirty read ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
์๊ฐ | ์๊ธ ์์ ํธ๋์ญ์ | ์๊ธ ์กฐํ ํธ๋์ญ์ |
09:37:00 | ํธ๋์ญ์ BEGIN | |
09:37:01 | ๊น๊ฐ๋ ์ฌ์ ์๊ธ ์กฐํ: 250๋ง์ | |
09:37:02 | ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ 300๋ง์์ผ๋ก UPDATE | ํธ๋์ญ์ BEGIN |
09:37:03 | ๊น๊ฐ๋ ์ฌ์ ์๊ธ ์กฐํ: 250๋ง์ | |
09:37:04 | ํธ๋์ญ์ COMMIT | |
09:37:05 | ๊น๊ฐ๋ ์ฌ์ ์๊ธ ์กฐํ: 300๋ง์ | |
09:37:06 | ํธ๋์ญ์ COMMIT |
์๊ธ ์กฐํ ํธ๋์ญ์ ์์ ๊น๊ฐ๋ ์ฌ์์ ์๊ธ์ ์กฐํํ๋ ๋๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฒ ์คํํ์ ๋ ์ฒซ ๋ฒ์งธ๋ 250๋ง์, ๋ ๋ฒ์งธ๋ 300๋ง์์ด ์กฐํ๋๋ค.
→ Non-Repeatable Read ๋ฐ์
์ด๋ ๊ฒ ๊ฐ์ ํธ๋์ญ์ ๋ด์์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์ฌ๋ฌ๋ฒ ์คํํ์ ๋ ๊ฐ์ row์ ๊ฐ์ด ์๋ก ๋ค๋ฅธ ๊ฒ์ Non-Repeatable Read(๋ฐ๋ณต ์ฝ๊ธฐ ๋ถ๊ฐ๋ฅ)์ด๋ผ๊ณ ํ๋ค.
3๏ธโฃ REPEATABLE READ (Level 2)
REPEATABLE READ๋ MVCC๋ฅผ ํตํด ํธ๋์ญ์ ์ด ์์๋๊ธฐ ์ ์ ์ปค๋ฐ๋ ๋ฐ์ดํฐ๋ง ์กฐํํ ์ ์๋ค.
ํ ํธ๋์ญ์ ๋ด์์ ํ ๋ฒ ์ฝ์ ๋ฐ์ดํฐ๋ ๋ฐ๋์ง ์๋๊ฒ์ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ Non-Repeatable Read ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
์ผ๋ฐ์ ์ธ RDBMS๋ ๋ณ๊ฒฝ ์ ์ ๋ ์ฝ๋๋ฅผ undo ๊ณต๊ฐ์ ๋ฐฑ์ ํด๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ณ๊ฒฝ ์ /ํ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ์กด์ฌํ๋ฏ๋ก, ๋์ผํ ๋ ์ฝ๋์ ๋ํด ์ฌ๋ฌ ๋ฒ์ ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋ค๊ณ ํ์ฌ ์ด๋ฅผ MVCC(Multi-Version Concurrency Control, ๋ค์ค ๋ฒ์ ๋์์ฑ ์ ์ด)๋ผ๊ณ ๋ถ๋ฅธ๋ค. MVCC๋ฅผ ํตํด ํธ๋์ญ์ ์ด ๋กค๋ฐฑ๋ ๊ฒฝ์ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ณต์ํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, ์๋ก ๋ค๋ฅธ ํธ๋์ญ์ ๊ฐ์ ์ ๊ทผํ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์๋ค. ๊ฐ๊ฐ์ ํธ๋์ญ์ ์ ์์ฐจ ์ฆ๊ฐํ๋ ๊ณ ์ ํ ํธ๋์ญ์ ๋ฒํธ๊ฐ ์กด์ฌํ๋ฉฐ, ๋ฐฑ์ ๋ ์ฝ๋์๋ ์ด๋ ํธ๋์ญ์ ์ ์ํด ๋ฐฑ์ ๋์๋์ง ํธ๋์ญ์ ๋ฒํธ๋ฅผ ํจ๊ป ์ ์ฅํ๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ถํ์ํด์ง๋ค๊ณ ํ๋จํ๋ ์์ ์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐฑ๊ทธ๋ผ์ด๋ ์ฐ๋ ๋๋ฅผ ํตํด ์ญ์ ํ๋ค.
→ MVCC๋ฅผ ํตํด ํ ํธ๋์ญ์ ๋ด ๋์ผ ๊ฒฐ๊ณผ ๋ณด์ฅ
์ด ๊ฒฉ๋ฆฌ ์์ค์ MySQL(MariaDB)์ default ๊ฒฉ๋ฆฌ ์์ค์ด๋ค.
ํ์ง๋ง REPEATABLE READ๋ ์๋ก์ด ๋ ์ฝ๋์ ์ถ๊ฐ๋๋ ๊ฒฝ์ฐ์ ๋ถ์ ํฉ์ด ์๊ธธ ์ ์๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก๋ ํธ๋์ญ์ ์ด ์์๋๊ธฐ ์ ์ ์ปค๋ฐ๋ ๋ฐ์ดํฐ๋ง ์กฐํํ์ง๋ง ์๋ก์ด ๋ ์ฝ๋์ ์ถ๊ฐ๊น์ง๋ ๋ง์ง ์๊ธฐ ๋๋ฌธ์ ํธ๋์ญ์ ์ด ๋๋๊ธฐ ์ ์ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ํด ์ถ๊ฐ๋ ๋ ์ฝ๋๊ฐ ๋ฐ๊ฒฌ๋ ์ ์๋๋ฐ, ์ด๋ฅผ ์ ๋ น ์ฝ๊ธฐ(Phantom Read)๋ผ๊ณ ํ๋ค.
๐ค ์ธ์ Phantom Read๊ฐ ๋ฐ์ํ๋ ๊ฑธ๊น?
์๊ฐ | ์๊ธ์ด 300 ์ด์์ธ ์ง์ ์กฐํ ํธ๋์ญ์ | ์๊ธ 350์ธ ์ ์ ์ฌ์ row ์ฝ์ ํธ๋์ญ์ |
09:37:00 | ํธ๋์ญ์ BEGIN | |
09:37:01 | ์๊ธ 300 ์ด์ ์ง์ ์กฐํ: 1๋ช
SELECT WHERE salary >= 300 FOR UPDATE |
ํธ๋์ญ์ BEGIN |
09:37:02 | ๋ฐ๋ค๋ผ ์ฌ์ ์ฝ์ : ์๊ธ 300๋ง์ | |
09:37:03 | ํธ๋์ญ์ COMMIT | |
09:37:04 | ์๊ธ 300 ์ด์ ์ง์ ์กฐํ: 2๋ช
SELECT WHERE salary >= 300 FOR UPDATE !!! Phantom Read ๋ฐ์!!! |
|
09:37:05 | ํธ๋์ญ์ COMMIT |
์๊ธ์ด 300 ์ด์์ธ ์ง์์ ์กฐํํ ๋ SELECT FOR UPDATE๋ฅผ ์ด์ฉํด ์๊ธ์ด 300 ์ด์์ธ ์ง์๋ค์ ๋ํด ์ฐ๊ธฐ ์ ๊ธ์ ๊ฑธ์๋ค.
ํด๋น ๊ตฌ๋ฌธ์ ๋ฒ ํ์ ์ ๊ธ(๋น๊ด์ ์ ๊ธ, ์ฐ๊ธฐ ์ ๊ธ)์ ๊ฑฐ๋ ๊ฒ์ด๋ค. (๋ ๋ฐ์ดํฐ ์์ ํ๋ ค๊ณ SELECT ํ๋ ์ค์ด๋๊น ๋ค๋ฅธ์ฌ๋๋ค์ ๋ฐ์ดํฐ์ ์๋์ง๋ง!!~) ์ ๊ธ ์๋ ์ฝ๊ธฐ๋ ํ ์ด๋ธ์ ๋ณ๊ฒฝ์ด ์ผ์ด๋์ง ์๋๋ก ํ ์ด๋ธ์ ์ ๊ธ์ ๊ฑธ๊ณ undo ๋ก๊ทธ๊ฐ ์๋ ํ ์ด๋ธ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ค. ๋ฝ์ ํธ๋์ญ์ ์ด ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ ๋ ๋ ํด์ ๋๋ค.
์๊ธ์ด 350๋ง์์ธ ๋ฐ๋ค๋ผ ์ฌ์์ ์ฝ์ ํ ๋ ์ผ๋ฐ์ ์ธ DBMS๋ ๊ฐญ๋ฝ์ด ์กด์ฌํ์ง ์์ผ๋ฏ๋ก salary >= 300 ์ธ ๋ ์ฝ๋๋ง ์ ๊ธ์ด ๊ฑธ๋ฆฐ ์ํ์ด๋ค. ๋ฐ๋ผ์ ์ ์ ์ฌ์ ์ฝ์ ์์ฒญ์ ์ ๊ธ ์์ด ์ฆ์ ์คํ๋๋ค.
๊ทธ ํ ์๊ธ 300 ์ด์ ์ง์ ์กฐํ ํธ๋์ญ์ ์ด ๋์ผํ ์ฐ๊ธฐ ์ ๊ธ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ค์ ํ๋ฒ ์กฐํํ๋ฉด, ์ด๋ฒ์๋ 2๊ฑด์ ๋ฐ์ดํฐ๊ฐ ์กฐํ๋๋ค.
์ด๋ ๋ฏ ๋ค๋ฅธ ํธ๋์ญ์ ์์ ์ํํ ์์ ์ ์ํด ๋ ์ฝ๋๊ฐ ๋ณด์๋ค ์๋ณด์๋ค ํ๋ ํ์์ Phantom Read ๋ผ๊ณ ํ๋ค.
๋๋ถ๋ถ์ RDBMS๋ REPEATABLE READ ๊ฒฉ๋ฆฌ ์์ค์์ Phantom Read ํ์์ด ๋ฐ์ํ์ง๋ง MySQL(MariaDB)์ ๋ค๋ฅธ RDBMS์ ๋ค๋ฅด๊ฒ ํน์ํ Gap Lock์ด ์กด์ฌํด ๋์์ด ๋ค๋ฅธ ๋ถ๋ถ์ด ์์ด ์ผ๋ฐ์ ์ผ๋ก Phantom Read๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
๐คง MySQL์ Gap Lock
๋ ์ฝ๋์ ๋ ์ฝ๋ ์ฌ์ด์ ๊ฐ๊ฒฉ์ ์ ๊ถ ๋ ์ฝ๋์ ์์ฑ, ์์ ๋ฐ ์ญ์ ๋ฅผ ์ ์ดํ๋ค.
์๋ฅผ ๋ค์ด ํ์ฌ ์ฑ์ด J๋ก ์์ํ๋ ๋ ์ฝ๋๊ฐ Jo, Joe 2๊ฐ๊ฐ ์๋ค๊ณ ํ์. ๊ทธ๋ฆฌ๊ณ ์ธ์ ๋ ์ง ๋ค๋ฅธ ๋ฐ์ดํฐ๋ค ex) Jang, Jeong, Jung ์ด ์ถ๊ฐ๋ ์ ์๋ค. ๋ฐ๋ผ์ ํ์ฌ ํธ๋์ญ์ ์์ ์กฐํ๋ฅผ ํ ๋, ๋ค๋ฅธ ํธ๋์ญ์ ์์ ์์์ ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ๋์ง ์๋๋ก ์ ๊ทธ๋ ค๋ฉด
SELECT * FROM member WHERE last_name LIKE "J%" FOR UPDATE; // ์ฐ๊ธฐ ์ ๊ธ(๋ฒ ํ๋ฝ)
SELECT * FROM member WHERE last_name LIKE "J%" LOCK IN SHARE MODE; // ์ฝ๊ธฐ ์ ๊ธ(๊ณต์ ๋ฝ)
์์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์คํํด์ผ ํ๋ค.
์ฌ๊ธฐ์ SELECT … FOR UPDATE ๊ตฌ๋ฌธ์ ๋ฒ ํ์ ์ ๊ธ(๋น๊ด์ ์ ๊ธ, ์ฐ๊ธฐ ์ ๊ธ)์ ๊ฑฐ๋ ๊ฒ์ด๋ค.
์ฝ๊ธฐ ์ ๊ธ์ ๊ฑธ๋ ค๋ฉด LOCK IN SHARE MODE ๊ตฌ๋ฌธ์ ์ฌ์ฉํด์ผ ํ๋ค. ๋ฝ์ ํธ๋์ญ์ ์ด ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ๋ ๋ ํด์ ๋๋ค.
REPEATABLE READ์ Phantom Read์ ๊ด๋ จํด ๋์์ด ๋์๋ ๋ธ๋ก๊ทธ๋ฅผ ์ฒจ๋ถํ๋ค.
4๏ธโฃ SERIALIZABLE
SERIALIZABLE์ ๊ฐ์ฅ ์๊ฒฉํ ๊ฒฉ๋ฆฌ ์์ค์ผ๋ก, ์ด๋ฆ ๊ทธ๋๋ก ํธ๋์ญ์ ์ ์์ฐจ์ ์ผ๋ก ์งํ์ํค๋ ๊ฒฉ๋ฆฌ์์ค์ด๋ค.
SELECT ... FOR UPDATE์ ํน์ row๋ค์๋ง lock์ ๊ฑฐ๋ ๋ฐ๋ฉด SERIALIZABLE์์๋ ์ ์ฒด์ lock์ ๊ฑด๋ค๋ ์ฐจ์ด์ ์ด ์๋ค.
(RDBMS๋ง๋ค ์ฐจ์ด๊ฐ ์์ด ๋ชจ๋ RDBMS๊ฐ SERIALIZABLE ๊ฒฉ๋ฆฌ ์์ค์ผ ๋ ์ ์ฒด lock์ ๊ฑฐ๋ ๊ฒ์ ์๋๋ค.)
SERIALIZABLE์์ ์ฌ๋ฌ ํธ๋์ญ์ ์ด ๋์ผํ ๋ ์ฝ๋์ ๋์ ์ ๊ทผํ ์ ์์ผ๋ฏ๋ก, ์ด๋ ํ ๋ฐ์ดํฐ ๋ถ์ ํฉ ๋ฌธ์ ๋ ๋ฐ์ํ์ง ์๋๋ค. ํ์ง๋ง ํธ๋์ญ์ ์ด ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด์ผ ํ๋ฏ๋ก ๋์ ์ฒ๋ฆฌ ์ฑ๋ฅ์ด ๋งค์ฐ ๋จ์ด์ง๋ค.
https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
https://mangkyu.tistory.com/299
https://dololak.tistory.com/446
https://breakcoding.tistory.com/406
'Study' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์คํ์์ค] Spring Boot ํ๋ก์ ํธ ์ปจํธ๋ฆฌ๋ทฐํฐ ๋๊ธฐ (0) | 2024.04.29 |
---|---|
[Java] Method Area๋ Heap ์์ญ์ด ์๋๋ค! (1) | 2024.02.19 |
[Java] ์๋ฐ ๋ฐํ์ ๋ฐ์ดํฐ ์์ญ(Runtime Data Area) (0) | 2024.02.19 |
[Java] ๋ณ์์ ๊ฐ์ฒด ๋ฐ์ดํฐ ์ ์ฅ (0) | 2024.02.17 |
[Java] ๊ฐ์ฒด๋น๊ต ์ equals()์ hashcode() ๋ ๋ค ์ฌ์ ์ํด์ผ ํ๋ ์ด์ (0) | 2024.02.13 |