## 동시성 구현 사례 ##

1. 일련번호 할당(=채번)을 이용한 동시성 높이기

 
  (1) 채번으로 가장 좋은 방법은 Sequence를 이용하는 방법
  (2) Sequence를 시용하지 못할때 사용하는 방법

       - 데이터가 삽입되는 시점에 실시간으로 현재의 MAX 값을 취해 1만큼 증가시킨 값을 이용하는 방식

          => PK제약 같은 예외처리를 통하여 동시성 제어(ex : 동시에 Insert 시)

       - MAX 값을 관리하는 별도의 채번 테이블에서 값을 가져오는 방식 -


- 번호 할당을 위한 Table -

 create table seq_tab (
  gubun varchar2(1),
  seq   number,
  constraint pk_seq_tab primary key(gubun, seq)
  )organization index;



- 현재의 값에 1을 증가 시켜 사용자에게 리턴하는 Function -

 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;
 /



- 위의 Table과 Function을 이용하여 채번되는 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;
/

      - 위의 Transaction이 어떠한 이유로 Insert 후 Rollback 되었을 경우
         => Insert 전의 Update만 commit 되어 일관성 깨짐
      - seq_nextval Function에서 Commit을 안하고 종료 하였을 경우
        => Transaction이 종료 될때까지 seq_tab(채번) Table에 Lock 발생

# 해결 방안 : "autonomous_transaction" 이용 - Main Transaction과는 별도로 Sub Transaction만 Commit하는 기능 제공



create or replace function seq_nextval(l_gubun number) return number as
 

 pragma autonomous_transaction; 

 
  l_new_seq seq_tab.seq%type;
begin
.
.


2. 선분이력 정합성 유지

    => 선분이력의 DML(Update, Insert, Delete) 실행으로 발생할 수 있는 동시성 문제(정합성 등) 해결 사례

\- 점이력   : Data의 변경시점만을 관리 => Data + 변경시점
\- 선분이력 : Data의 변경된 시작 시점과 종료시점을 함께 관리 => Data + 시작시점 + 종료시점 



   


- 최종 선분이력을 새로운 선분이력으로 변경하는 Transaction-

declare

  cur_dt varchar2(14);

begin

   cur_dt := to_char(sysdate, 'yyyymmddhh24miss') ;

  update 부가서비스이력
   set 종료일시 = to_date(:cur_dt, 'yyyymmddhh24miss') - 1/24/60/60
   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 되는 Transaction
      - 선행 Transaction이 작업 중일때 후행 Transaction이 동일 Data에 대하여 변경 작업을 하여 일관성이 깨짐

# 해결 방안 : 아래의 구문을 Transaction내의 Update 전에 추가

 select 고객ID
    from 부가서비스이력
   where 고객ID = 1
     and 종료일시 = to_date('99991231235959', 'yyyymmddhh24miss')
     for update nowait ;

  select 고객ID
    from 고객
   where 고객ID = 1
     for update nowait ;

      - Transaction 내에서 DML 작업 전에 select for update를 이용하여 Transaction이 순차 진행을 할 수 있도록 함
      - 부가서비스이력이 없는 고객도 Lock 설정이 될 수 있도록 상위 엔티티인 고객 Table에도 select for update 설정