-- 마스터 테이블 생성 CREATE TABLE MAST( SEQ NUMBER , CNT NUMBER ); CREATE UNIQUE INDEX UK_MAST_01 ON MAST (SEQ ASC); ALTER TABLE MAST ADD CONSTRAINT PK_MAST PRIMARY KEY (SEQ); -- 서브 테이블 생성 CREATE TABLE MAST_SUB( SEQ NUMBER , SUB_SEQ NUMBER ); CREATE UNIQUE INDEX UK_MAST_SUB_01 ON MAST_SUB (SEQ ASC, SUB_SEQ ASC); ALTER TABLE MAST_SUB ADD CONSTRAINT PK_MAST_SUB PRIMARY KEY (SEQ, SUB_SEQ); ALTER TABLE MAST_SUB ADD (CONSTRAINT FK_MAST_SUB_01 FOREIGN KEY (SEQ) REFERENCES MAST (SEQ)); -- 마스터 데이터 입력 INSERT INTO MAST SELECT ROWNUM SEQ, 10 CNT FROM DUAL CONNECT BY LEVEL <= 10; COMMIT; -- 서브 데이터 입력 INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,1); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,2); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,3); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,4); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,5); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,6); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,7); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,8); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,9); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,10); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,11); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,12); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,13); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,14); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,15); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,16); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,17); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,18); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,19); INSERT INTO MAST_SUB(SEQ,SUB_SEQ) VALUES(1,20); -- 이때 서브 데이터는 MAST 테이블의 SEQ값 기준으로 CNT 수만큼만 INSERT가 되어야 합니다. -- 그러므로 SUB_SEQ값이 11번 부터는 에러가 나서 입력 되지 않으면 됩니다.
위에 샘플로 만든 MAST 테이블의 PK인 SEQ값을 기준으로 CNT 개수만큼만 MAST_SUB 테이블에 넣고 싶은데요..
프로그램에서 위에 샘플처럼 20개를 넣는다고 하여도 MAST의 CNT 기준인 10개만 들어가고
나머지 11번부터 20번까지는 에러든 어떠한 방법이든 더이상 들어가지 못하도록 해야 합니다.
트리거로 해보려 했는데.. 트리거로 자기 자신을 바꿀 수는 없기 때문에 안되더군요..
뭔가 좋은 방법이 없을까요?
참고로 DB는 ORACLE 11G R2 입니다.
감사합니다..
마농님 답변 감사합니다.
제가 비슷하게 했다는 건 거의 똑같은데..
IF :NEW.sub_seq > v_cnt
THEN 문장에서 >= 로 했구요
에러 메세지는 좀 다르게 한것뿐입니다.
그리고 제가 아무래도 질문을 잘못 한듯 합니다.
마농님 말씀데로 제가 질문하고 싶은건 동시성제어 입니다.
좋은 방법이 없을가요?
역시 해당 업무에 대해서는 웹서버를 하나만 지정해서 돌려는 방법 뿐일까요?
서버 하나만으로 하는 경우 여러가지 문제점들이 또 발생해서..
DB 쪽에서 할 수 있는 방법은 없나 검토중입니다.
혹시 다른 분들께서 비슷한 경우에 해결 방법이 있으실까 해서 질문했습니다.
보통 오라클 시퀀스 객체를 이용하는데요.
건수가 정해진 경우라면 사용자 시퀀스를 만들어 사용하는 방법도 있습니다.
mast 테이블에 cnt 외에 현재 사용중인 sub_seq 를 저장하는 방안입니다.
mast_sub 입력 프로세스
1. mast 를 for update 로 락을 걸어 sub_seq 와 cnt 를 select 합니다.
2. mast 의 sub_seq 가 cnt 와 같으면 Rollback, 오류메시지처리
3. mast 의 sub_seq 가 cnt 보다 작으면 다음단계 진행
4. mast 의 sub_seq 를 1 증가 시키고 바로 COMMIT 하여 LOCK 해제
5. sub_seq + 1 을 이용하여 mast_sub 입력 진행
mast_sub 입력 프로세스 는 mast 로부터 채번을 하면서 Lock 를 설정합니다.
Lock 설정으로 동시성은 조금 떨어지지만
제약조건을 만족시키면서도 Lock 시간을 최소화합니다.
두가지 사항은 상반되는 상황입니다.
(동시성을 높이는것) VS (제약조건을 준수하는것)
제약조건을 반드시 준수해야 하는 상황으로 판단이 되며, 그러려면 락은 필수입니다.
대신 락 시간을 최소화해야겠지요.
락 걸고 모든 처리를 다 마무리하고 락을 해제한다면 동시성은 크게 저하가 되겠지요.
하지만 채번과정에서만 락을 걸고 나머지 처리과정에서는 락을 걸지 않는다면?
동시성이 크게 저하되지는 않겠지요.
(락 > 조회 > 업데이트 > 락해제) 이 일련의 채번 과정은 오래 걸릴 과정은 아니죠.
채번과정만 입력과정과는 별개로 순식간에 진행되므로 크게 무리가 되지 않을것 같습니다.