by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

동시성 구현 사례




동시성 구현 사례

채번 하는 방법

  1. Sequence 이용하는 방법
  2. 데이터가 삽입되는 시점에 실시간으로 현재의 MAX값을 취해 1만큼 증가시킨 값을 이용
    • 문제점 : 실시간으로 MAX값을 얻어 처리할 때는 두 개의 트랜잭션이 동시에 같은 값을 읽을 경우, insert 하려는 순간 PK제약에 위배. ? Exception 처리를 통해 그다지 어렵지 않게 동시성을 제정할 수 있음
  3. MAX값을 관리하는 별도의 채번 테이블에서 가져오는 방식
    • 문제점 : 채번 테이블을 사용할 때는 채번 후 다음 처리로 진행하기 전에 채번 테이블 값을 1만큼 증가시키는 갱신을 수행해야 함
      
      -- 테이블 생성
      Create table seq_tab (
      Gubun varchar2(1),
      Seq    number,
      Constraint pk_seq_tab primary key(gubun,seq))
      
      -- Procedure 생성
      Create or replace function seq_nextval (l_gubun number) return number
      As
      /** pragma autonomous_transaction; **/
      l_new_seq seq_tab.seq%type;
      
      begin
       update seq_tab
         set    seq = seq + 1
         where gubun = l_gubun;
      
         select seq into l_new_seq
         from seq_tab
         where gubun = l_gubun;
      
      
         commit;
         return l_new_seq;
      end;
      /
      
      
      --Transaction
      Begin
       Update tab1 set col1 = :x where col2 = :y;
      
      Insert into tab2 values
      (seq_nextval(123), :x, :y, :z);
      
      Loop
       --do anything....
      End loop;
      
      Commit;
      
      Exception
       When others then
        Rollback;
      End;
      
      


    • 문제점은 커밋 시점이다. 만약 앞서 정의한 seq_nextval 함수처럼 커밋을 한다면, 어떤 이유에서 메인 트랜잭션이 라인 4 insert 이후에 롤백될 경우 문제가 생긴다. 즉 update(Function의 update)는 이미 커밋된 상태가 되어 데이터의 일관성이 깨지게 된다.
    • 만약 seq_nextval함수에서 커밋을 안하고 함수를 빠져나오면 메인 트랜잭션이 모두 종료될 때까지 채번 테이블에 Lock이 걸린 상태가 유지 되므로 동시 채번이 빈번히 발생하는 상황에서 심각한 성능 저하를 일으키게 될 것이다.
    • 'autonomous 트랜잭션'이라고 하여 서브 트랜잭션만 따로 커밋하는 기능을 제공한다.

선분이력 정합성 유지

Declare
 cur_dt varchar2(14);
begin
① cur_dt := to_char(sysdate, 'yyyymmddhh24miss');

② update 부가서비스이력
   Set     종료일시 = to_date(:cur_dt, 'yyyymmddhh24miss');
   Where  고객ID = 1
   And     부가서비스ID = 'A'
   And     종료일시 = to_date('99991231235959', 'yyyymmddhh24miss');

③ insert into 부가서비스이력(고객ID, 부가서비스ID,시작일시,종료일시)
   Values(1, 'A', to_date(:cur_dt, 'yyyymmddhh24miss'),
   To_date('99991231235959', 'yyyymmddhh24miss'));

④ commit;
End;
    • 이 트랜잭션은 기존의 선분이력을 끊고 새로운 이력 레코드를 추가하는 전형적인 처리 루틴이다.
    • 신규 등록 건이면 ②번 update문에서 실패하고 ③번에서 한 건이 insert될 것이다.
  • 만일 첫 번째 트랜잭션이 ①을 수행하고 ②로 진입하기 직전에 어떤 이유에서건 두 번째 트랜잭션이 동일 이력에 대해 ①~④를 먼저 진행해 버린다면 선분이력이 깨지게 된다. 따라서 트랜잭션이 순차적으로 진행할 수 있도록 직렬화 장치를 마련해야 한다.
    • ①번 문장을 수행하기 직전에 "select for update"문을 이용해 해당 레코드에 Lock을 설정 하면 된다.
    • 하지만 부가서비스이력에 Lock을 걸어 동시성을 관리하려 한다면 기존에 부가서비스이력이 전혀 없던 고객일 경우 Lock이 걸리지 않는다. 그러면 동시에 두개 트랜?신이 ③번 insert문으로 진입할 수 있고, 결과적으로 시작일시는 다르면서 종료일시 같은 두 개의 이력 레코드가 생긴다.
    • 따라서 부가서비스이력의 상위 엔티티인 고객 테이블에 Lock을 설면 완벽하게 동시성 제어를 할 수 있다.

문서에 대하여

  • 최초작성자 : 미녀씨
  • 최초작성일 : 2009년 10월 22일
  • 이 문서는 오라클클럽 코어 오라클 데이터베이스 스터디 모임에서 작성하였습니다.
  • 이 문서의 내용은 (주)비투엔컬설팅에서 출간한 '오라클 성능 고도화 원리와 해법I'를 참고하였습니다.

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.