. 비관적 동시성 제어 
           - 사용자 들이 같은 데이터를 동시에 수정 할 것이라 가정
           - 한 사용자가 데이터를 읽는 시점에 Lock를 걸고 조회 또는 갱신 처리가 완료 될때까지 이를 유지

 

 . 낙관적 동시성 제어
          - 사용자들이 같은 데이터를 동시에 수정하지 않은 것이라 가정
          - 데이터를 읽을 때에는 Lock을 설정하지 않음
          - Lock을 유지하는 시간이 매우 짧아져 동시성을 높이는데 유리
              But, 다른 사용자가 같은 데이터를 변경했는지 검사하고 그에 따라 분기해나가는 튜닝 절차가 필요


(1) 비관적 동시성 제어

                                                                                       

SELECT 적립포인트 , 방문횟수, 최근방문일시, 구매실적 FROM 고객
WHERE 고객번호 = : CUST_NUM FOR UPDATE;

-- 새로운 적립포인트 계산
UPDATE 고객 SET 적립포인트 = : 적림포인트 WHERE 고객번호 = : CUST_NUM

                                                                                       

 

  - SELECT 문에 FOR UPDATE를 사용하여 해당 고객 레코드에 LOCK을 걸어둔다면
    데이터가 잘못 갱신되는 문제를 방지할수 있음
    But,  시스템 동시성을 심각하게 떨어뜨릴 우려

 

 

                                                                                       

 for update nowait --> 대기 없이 Exception (ORA-00054)을 던짐
 for update wait 3 --> 3초 대기 후 Exception (ORA-30006)을 던짐

                                                                                       

 

  - wait또는 nowait 옵션을 사용하면, 다른 트랜잭션에 의해 Lock이 걸렸을 때
    Exception을 만나게 되므로 "다른 사용자에 의해 변경 중이므로 다시 시도하십시오"
    동시성을 증가시키게 됨

 

(2) 낙관적 동시성 제어

 

                                                                                       

----- 고객번호를 제외하고 4개 컬럼을 참조

select 적립포인트, 방문횟수, 최근방문일시, 구매실적 into :a, :b, :c, :d
from 고객
where 고객번호 = : cust_num;

 

-- 새로운 적립포인트 계산

update 고객 set 적립포인트 =: 적립포인트
where 고객번호 := cust_num
and 적립포인트 = : a
and 박문횟스 = : b
and 최근방문일시 =: c
and 구매실적 =: d

 

if sql%rowcount = 0 then
 alter ('다른 사용자에 의해 변경되었습니다.');
and if;

 

 

----- 대상 테이블에 최종 변경일시 관리하는 칼럼   mod_dt : 최종변경일시 관리 칼럼
select 적립포인트, 방문횟수, 최근방문일시, 구매실적
into :a, :b, :c, :d, :mod_dt
from 고객
where 고객번호 = : cust_num;

-- 새로운 적립포인트 계산

update 고객 set 적립포인트 =: 적립포인트
where 고객번호 := cust_num
and 변경일시 = :mod_dt;

if sql%rowcount = 0 then
 alter ('다른 사용자에 의해 변경되었습니다.');
and if;

 

----- update 전에 select를 한번 더 수행

select 고객번호
from 고객
where 고객번호 =: cust_num
and 변경일시 = : mod_dt
for update nowait;

 

----- 오라클 10g 부터 사용하는 ora_rowscn을 활용

create table t
ROWDEPENDENCIES
nologging
as
select * from scott.emp;

 

select 적립포인트, 방문횟수, 최근방문일시, 구매실적, ora_rowscn
  into :a, :b, :c, :d, :rowscn
  from 고객
 where 고객번호 = :cust_num;

 

-- 새로운 적립포인트 계산

update 고객
   set 적립포인트 = :적립포인트,
       변경일시 = SYSDATE
 where 고객번호 = :cust_num
   and ora_rowscn = :rowscn ;

 

if sql%rowcount = 0 then
  alert('다른 사용자에 의해 변경되었습니다.');
end if; 

                                                                                       

 

  . ora_rowscn과 scn_to_timestamp 함수를 이용하면 특정 레코드의 갱신시점을 알수 있음

   but , 매핑 테이블의 보관주기는 5일