SELECT Lock

๋ณดํ†ต InnoDB ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ๋ ˆ์ฝ”๋“œ์— ์•„๋ฌด๋Ÿฐ ์ž ๊ธˆ์„ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค.(=Non Locking Consistent Read) ๋‹จ์ˆœ ์กฐํšŒํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์ž ๊ธˆ์„ ๊ฑธ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ, ์ฝ์€ ๋ ˆ์ฝ”๋“œ์˜ ์ปฌ๋Ÿผ ๊ฐ’์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ€๊ณตํ•ด์„œ ์—…๋ฐ์ดํŠธ ํ•  ๋–„์—” ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ์ž ๊ธˆ์„ ๊ฑธ์–ด์•ผ ํ•œ๋‹ค. FOR SHARE์™€ FOR UPDATE์ ˆ์„ ์ถ”๊ฐ€ํ•ด์„œ ์ฝ๊ธฐ ๋ฐ ๋ฐฐํƒ€ ์ž ๊ธˆ์„ ๊ฑธ ์ˆ˜ ์žˆ๊ณ , ์ฐจ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • FOR SHARE : ์ฝ์€ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ฝ๊ธฐ ์ž ๊ธˆ์„ ๊ฑด๋‹ค. ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์€ ์ฝ๊ธฐ ์ž ๊ธˆ์„ ๊ฑธ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฐฐํƒ€ ์ž ๊ธˆ์€ ๊ฑธ ์ˆ˜ ์—†๋‹ค.(S-lock, Shared Lock)

  • FOR UPDATE : ์ฝ์€ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋ฐฐํƒ€ ์ž ๊ธˆ์„ ๊ฑด๋‹ค. ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์€ ์ฝ๊ธฐ ์ž ๊ธˆ๋„ ๋ฐฐํƒ€ ์ž ๊ธˆ๋„ ๊ฑธ ์ˆ˜ ์—†๋‹ค.(X-lock, Exclusive Lock)

InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์—์„œ ์กฐ๊ธˆ ๋‹ค๋ฅธ ์ ์€, ์ž ๊ธˆ ์—†๋Š” ์ฝ๊ธฐ๊ฐ€ ์ง€์›๋˜๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ๋ ˆ์ฝ”๋“œ๊ฐ€ FOR UPDATE ์ฟผ๋ฆฌ์— ์˜ํ•ด์„œ ์ž ๊ฒจ์ง„ ์ƒํƒœ๋ผ๋„, FOR SHARE๋‚˜ FOR UPDATE ์ ˆ์„ ๊ฐ€์ง€์ง€ ์•Š์€ ๋‹จ์ˆœ SELECT ์ฟผ๋ฆฌ๋Š” ์ •์ƒ์ ์œผ๋กœ ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž ๊ธˆ ํ…Œ์ด๋ธ” ์„ ํƒ

SELECT *
FROM employees e
         INNER JOIN dept_emp de ON de.emp_no = employees.emp_no
         INNER JOIN departments d ON d.dept_no = de.dept_no
    FOR
UPDATE;

์œ„ ์ฟผ๋ฆฌ๋Š” employees, dept_emp, departments ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด ์ž ๊ธˆ์„ ๊ฑธ์ง€๋งŒ, employees ํ…Œ์ด๋ธ”์—๋งŒ ์ž ๊ธˆ์„ ๊ฑธ๊ณ  ์‹ถ๋‹ค๋ฉด FOR UPDATE ์ ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

SELECT *
FROM employees e
         INNER JOIN dept_emp de ON de.emp_no = employees.emp_no
         INNER JOIN departments d ON d.dept_no = de.dept_no
    FOR
UPDATE OF e;

NOWAIT & SKIP LOCKED

ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์œผ๋ ค๋Š”๋ฐ, FOR UPDATE ์ ˆ์— ์˜ํ•ด ์ž ๊ฒจ์ ธ ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์€ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ž ๊ธด ์ƒํƒœ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์˜ ํ•ด์ œ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผํ•˜๊ฑฐ๋‚˜, ์‹ฌ๊ฐํ•œ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜ค๋ฅ˜ ๋“ฑ์œผ๋กœ ํ•ด์ œ๊ฐ€ ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ innodo_lock_wait_timeout์— ์„ค์ • ๋œ ์‹œ๊ฐ„๊นŒ์ง€ ๋Œ€๊ธฐํ•ด์•ผ ํ•œ๋‹ค.

SELECT *
FROM employees
WHERE emp_no = 10001
    FOR
UPDATE NOWAIT;

ํ•˜์ง€๋งŒ ์œ„์ฒ˜๋Ÿผ NOWAIT ์ ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ž ๊ฒจ์ ธ ์žˆ์„ ๊ฒฝ์šฐ์—” ๋ฐ”๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด์„œ ์ฟผ๋ฆฌ๋ฅผ ์ฆ‰์‹œ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค. ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์œผ๋กœ SKIP LOCKED ์ ˆ์ด ์žˆ๋Š”๋ฐ, ์ด๋Š” ์ž ๊ธด ๋ ˆ์ฝ”๋“œ๋Š” ๊ฑด๋„ˆ๋›ฐ๊ณ  ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.(๊ฐ™์€ ์ฟผ๋ฆฌ๋ผ๋„ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” NOT-DETERMINISTIC ์ฟผ๋ฆฌ๊ฐ€ ๋œ๋‹ค.)

์˜ˆ์‹œ๋ฅผ ํ†ตํ•œ ํ™œ์šฉ ๋ฐฉ๋ฒ•

NOWAIT์™€ SKIP LOCKED ๊ธฐ๋Šฅ์€ ํ(Queue)์™€ ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ MySQL ์„œ๋ฒ„์—์„œ ๊ตฌํ˜„ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฟ ํฐ ๋ฐœ๊ธ‰ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

  • ํ•˜๋‚˜์˜ ์ฟ ํฐ์€ ํ•œ ์‚ฌ์šฉ์ž๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

  • ์ฟ ํฐ์˜ ๊ฐœ์ˆ˜๋Š” 1000๊ฐœ ์ œํ•œ

  • ์„ ์ฐฉ์ˆœ์œผ๋กœ ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐœ๊ธ‰

CREATE TABLE coupon
(
    coupon_id     BIGINT      NOT NULL,
    owned_user_id BIGINT      NULL DEFAULT 0,
    coupon_code   VARCHAR(15) NOT NULL,
#   ...
    primary key (coupon_id),
    INDEX ix_owneduserid (owned_user_id)
);

ํ…Œ์ด๋ธ”์€ ์œ„์™€ ๊ฐ™๊ณ  ์ฟ ํฐ ๋ฐœ๊ธ‰ ๊ณผ์ •์„ ๊ฐ„๋žตํ™”ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

BEGIN;

SELECT *
FROM coupon
WHERE owned_User_id = 0
ORDER BY coupon_id ASC
LIMIT 1
FOR
UPDATE;

-- ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง ์ˆ˜ํ–‰

UPDATE coupon
SET owned_user_id = ?
WHERE coupon_id = ?;

COMMIT;

์œ„ ์ฟผ๋ฆฌ๋ฅผ ๋™์‹œ์— 1000๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•˜๊ฒŒ ๋˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„๋Š” ๊ทธ ์š”์ฒญ๋งŒํผ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•ด ์œ„์˜ ํŠธ๋žœ์žญ์…˜์„ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•  ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ๊ฐ€์žฅ ์ฒซ ํŠธ๋žœ์žญ์…˜๋งŒ FOR UPDATE ์ฟผ๋ฆฌ๋กœ ์ธํ•ด ์ž ๊ธˆ์„ ๊ฑธ๊ณ  ๋‚˜๋จธ์ง€ 999๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์€ ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ž ๊ฒจ์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๊ธฐํ•˜๊ฒŒ ๋˜๊ณ , ๊ฒฐ๊ตญ์—” ๋Œ€๊ธฐ ์‹œ๊ฐ„ ๋™์•ˆ ์ž ๊ธˆ์„ ํš๋“ํ•˜์ง€ ๋ชปํ•ด์„œ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ UPDATE SKIP LOCKED ์ ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž ๊ธˆ ๋œ ๋ ˆ์ฝ”๋“œ๋Š” ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋‹ค์Œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์„œ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— 1000๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์„ ์„ฑ๋Šฅ ์ €ํ•˜ ์—†์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ ์„ ์€ ํŠธ๋žœ์žญ์…˜์„ ๋Œ€๊ธฐํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ , ๊ตต์€ ํ™”์‚ดํ‘œ๋Š” ์‹ค์ œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ๋ฆ„์„ ์˜๋ฏธํ•  ๋•Œ, SKIP LOCKED๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹ค์ œ๋กœ ๋Œ€๊ธฐํ•˜๋Š” ์‹œ๊ฐ„์€ ๋งค์šฐ ์งง์€ ์‹œ๊ฐ„(๋ ˆ์ฝฌ๋“œ ํ•œ ๊ฑด์„ ์Šคํ‚ตํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„)์ด๋ฏ€๋กœ 1000๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์„ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

Last updated

Was this helpful?