테마
버거원 매장은 주문마다 영수증과 대기 번호판에 오늘의 주문번호를 띄운다. 번호는 매장마다 매일 1번부터 시작하고, 카운터 POS와 키오스크 두 대가 같은 번호 체계를 쓴다. 매일 아침 개점 직후 첫 주문에서 하루 30 ~ 40개 매장의 키오스크나 POS가 "번호 발급 실패, 다시 주문해 주세요"를 띄운다. 그 뒤로는 하루 종일 괜찮다.
SHOP 매장: 200행 · 5블록 · SHOP_NO 'SH0001' · PKSHOP_RCPT_NUM 매장별 일별 번호(이 문제를 위해 더한 채번 테이블): SHOP_RCPT_NUM_PK (SHOP_NO, RCPT_DT) · LAST_NO · 하루 200행씩 생긴다-- PKG_POS.NEXT_RCPT_NO — 오늘의 주문번호
FUNCTION NEXT_RCPT_NO(p_shop VARCHAR2, p_dt VARCHAR2) RETURN NUMBER IS
v_no NUMBER;
BEGIN
SELECT LAST_NO + 1 INTO v_no
FROM SHOP_RCPT_NUM
WHERE SHOP_NO = p_shop AND RCPT_DT = p_dt
FOR UPDATE;
UPDATE SHOP_RCPT_NUM SET LAST_NO = v_no
WHERE SHOP_NO = p_shop AND RCPT_DT = p_dt;
RETURN v_no;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- 오늘 첫 주문이면 행을 만든다
INSERT INTO SHOP_RCPT_NUM (SHOP_NO, RCPT_DT, LAST_NO) VALUES (p_shop, p_dt, 1);
RETURN 1;
END;
[시간표 — 매장 SH0088 · 07:00 개점]
시각 카운터 POS (SID 140) 키오스크 1 (SID 166)
07:00:21.30 SELECT … FOR UPDATE → 0행 (NO_DATA_FOUND)
07:00:21.31 SELECT … FOR UPDATE → 0행 (NO_DATA_FOUND)
07:00:21.32 INSERT ('SH0088', '20131014', 1) → 1번
07:00:21.33 INSERT ('SH0088', '20131014', 1) → 기다림
07:00:22.90 결제 끝 · COMMIT → ORA-00001: unique constraint (DEV.SHOP_RCPT_NUM_PK) violated
→ 키오스크 "번호 발급 실패"
[V$LOCK — 07:00:22]
SID TYPE 대상 / 이름표 LMODE REQUEST BLOCK
140 TM SHOP_RCPT_NUM 3 0 0
140 TX 140 의 트랜잭션 6 0 1
166 TM SHOP_RCPT_NUM 3 0 0
166 TX 140 의 트랜잭션 0 4 0
[지난 2주 · 번호 발급 실패]
하루 31 ~ 42건 · 전부 그 매장의 그날 첫 번째 ~ 세 번째 주문 · 그 뒤로는 0건
같은 시각에 다른 매장끼리는 한 번도 기다리지 않았다
FOR UPDATE가 왜 이 충돌을 막지 못하는지 설명하시오.