동시성 제어 또는 트랜잭션 관리..... 예약시스템(인원오버) 0 2 1,352

by 박지훈 [PL/SQL] 동시성제어 트랜잭션 예약시스템 인원오버 [2022.08.19 12:00:55]


1. 상황은 이렇습니다. 

  예를 들어 100명 까지 받는 예약에서 101명이 들어온 케이습니다.

 

2. 간단히 로직은 이렇습니다.
(※ 참고로 예약이 가능한 여부가 인원체크를 포함 10개 항목 정도 있습니다.(시간 등)

 가. 예약 메인 패키지 호출
    PG_APPLY.MAIN();

 나. 메인 패키지 내 유효성 검사1~10 번 검사
   PG_APPLY.MAIN()

   IS

   BEGIN

      IF CHECK_1() = 'N' THEN --검사 프로시저 및 함수 호출
            RETURN '1번 이유 때문에 불가능....'
      END IF;
      IF CHECK_2() = 'N' THEN  --검사 프로시저 및 함수 호출
            RETURN '2번 이유 때문에 불가능....'
      END IF;    
      IF LIMIT_CHECK() = '인원오버' THEN  --검사 프로시저 및 함수 호출
             RETURN ''인원오버....'
      END IF;    

        .

        .
        .

      IF CHECK_10() = 'N' THEN  --검사 프로시저 및 함수 호출
             RETURN '10번 이유 때문에 불가능....'
      END IF;                 

      --모두 유효성을 통과 했다면 INSERT
      INSERT INTO TB_APPLY............................
          
      LOG();--로그 함수 호출

      COMMIT;
      

   END PG_APPLY.MAIN;
   
  다. 인원 체크 함수

  PG.APPLY.LIMIT_CHECK()    
  IS
  BEGIN

  현원       := SELECT COUNT(1) FROM TB_APPLY
  최대인원 := SELECT COL_1 FROM ....

  IF 현원 >= 최대 THEN
        RETURN '인원오버'  
  ELSE
       RETURN '신청가능'          
  END IF;

  END LIMIT_CHECK;


3. 총 예약 건수는  몇 백개 항목에 몇 십명씩 선택하여 대략 2만건 내외 입니다.(오픈 후 10분안에 만건 정도 처리. 수강신청이란 비슷하죠)
문제는 이중에 간혹 1~10/1000초 차이로 인원이 간혹 오버 됩니다.

4. 궁금한것은..
-인원이 오버 되는 이유가   'PG.APPLY.LIMIT_CHECK()--인원체크'후에 바로 INSERT 하지 않고 다른 체크 'CHECK_##()'함수를 실행 하는 동안 인원이 오버 되는 것인지..
-그렇다면 한 트랜잭션으로 묶던지 FOR UPDATE...를 활용해서 동시성제어를 해야 하는건지 헷갈리네요.
-그런데 오라클은 DML단위 트랜잭션이 된다니... 인원체크 후에 INSERT까지 어떻하면 한 트랜잭션으로 묶어야 할지 모르겠습니다.
-동시성제어도 생각해 봤는데... 위와 같은 구조에서는 적용이 맞는건지 모르겟습니다.

고견을 부탁드립니다.

 

by 마농 [2022.08.19 13:03:31]

"최대인원"이 저장되어 있는 테이블에 "신청인원" 컬럼 추가
"신청인원" 은 "최대인원" 을 넘지 않도록 체크 제약 설정
신청 테이블 자료 입력시 "신청인원" 갱신되도록 트리거 설정

-- 1. 컬럼 추가 --
ALTER TABLE tb_apply_limit ADD app_cnt NUMBER;
-- 2. 제약 설정 --
ALTER TABLE tb_apply_limit ADD CONSTRAINT check_limit CHECK app_cnt <= limit_cnt;
-- 3. 과거 자료 정비 --
UPDATE tb_apply_limit a
   SET app_cnt = (SELECT COUNT(*) FROM tb_apply WHERE id = a.id)
;
-- 4. 트리거 설정 --
CREATE OR REPLACE TRIGGER tri_tb_apply
AFTER INSERT ON tb_apply
FOR EACH ROW
BEGIN
    UPDATE tb_apply_limit
       SET app_cnt = app_cnt + 1
     WHERE id = :NEW.id
    ;
END;
/

 


by 박지훈 [2022.08.19 14:18:58]

먼저 답변 감사합니다.^^

트리거는 부하 때문에 생각을 안했는데 정확성을 위해서는 하는게 맞겠네요.

그리고 '신청인원'컬럼은 있었는데 간혹 운영자가 프로세스 무시하고 넣는 경우가 있어서(신청인원 컬럼 업뎃 안됨.)

셀렉트를 통한 '신청인원' 카운트를 했는데.... 운영적으로도 막고 제약까지 걸고 해야겠네요.

마농님 정말 감사합니다.

 

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입