테마
정산 등록 화면은 저장 버튼을 누르면 프로시저 P_REG_STLM을 부른다. 이 프로시저는 정산을 넣고, 포인트 적립 프로시저 P_ADD_POINT를 부른 뒤 화면에 'OK'를 돌려준다. 화면은 'OK'를 받으면 커밋하고 「등록 완료」를 띄운다.
지난달 조민우가 "등록 완료가 떴는데 목록에 없는 정산이 있다"며 세 건을 가져왔다. 세 건 모두 탈퇴 처리 중인 고객의 정산이었다. 정산팀 규정은 "포인트 적립이 실패해도 정산은 등록하고, 실패한 적립은 다음 날 다시 적립한다"이다.
T_ORD_STLM 정산: PK_T_ORD_STLM (STLM_SEQ) · 번호는 시퀀스 SQ_STLM_SEQT_CUS_POINT 고객 포인트(이 문제용): 고객마다 한 행 · PK (CUS_ID) · POINT_BALT_ERR_LOG 오류 기록(이 문제용): LOG_DT · PGM · KEY_VAL · MSGPROCEDURE P_ADD_POINT(p_cus_id VARCHAR2, p_amt NUMBER) IS
v_bal NUMBER;
BEGIN
SELECT POINT_BAL INTO v_bal FROM T_CUS_POINT WHERE CUS_ID = p_cus_id FOR UPDATE;
UPDATE T_CUS_POINT SET POINT_BAL = v_bal + ROUND(p_amt * 0.01) WHERE CUS_ID = p_cus_id;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- 포인트가 꼬이지 않게 되돌린다
INSERT INTO T_ERR_LOG (LOG_DT, PGM, KEY_VAL, MSG)
VALUES (SYSDATE, 'P_ADD_POINT', p_cus_id, SQLERRM);
END;
PROCEDURE P_REG_STLM(p_ord_seq NUMBER, p_cus_id VARCHAR2, p_amt NUMBER, o_rslt OUT VARCHAR2) IS
BEGIN
INSERT INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
VALUES (SQ_STLM_SEQ.NEXTVAL, p_ord_seq, p_cus_id, SYSDATE, p_amt);
P_ADD_POINT(p_cus_id, p_amt);
o_rslt := 'OK';
END;
-- 화면 : CALL P_REG_STLM(…) → o_rslt = 'OK' 이면 COMMIT, 아니면 ROLLBACK
[T_ERR_LOG — 지난달]
LOG_DT PGM KEY_VAL MSG
05/07 10:41:12 P_ADD_POINT CUS_000777 ORA-01403: no data found
05/14 15:02:40 P_ADD_POINT CUS_001203 ORA-01403: no data found
05/28 09:17:05 P_ADD_POINT CUS_001876 ORA-01403: no data found
[정산 등록 화면 로그 — 같은 시각]
P_REG_STLM 결과 'OK' → COMMIT → 「등록 완료」 (세 건 모두)
[T_ORD_STLM]
세 주문의 정산 0건 · 그 시각에 받은 정산 번호 412,118 · 412,907 · 413,560은 결번
[시험 — 연습 DB, 포인트 행이 없는 고객으로 한 번]
P_REG_STLM 직후 (화면 COMMIT 전)
SELECT COUNT(*) FROM T_ORD_STLM WHERE ORD_SEQ = :ord → 0
SELECT COUNT(*) FROM T_ERR_LOG WHERE KEY_VAL = :cus → 1