메뉴 건너뛰기

bysql.net

3. 비관적 vs. 낙관적 동시성 제어

2010.06.07 02:26

휘휘 조회 수:8210


  • 비관적 동시성 제어 (Pessimistic Concurrency Control)
    • 사용자들이 같은 데이터를 동시에 수정할것이라고 가정
    • 사용자가 데에터를 읽는 시점에 LOCK을 걸어 그 트랜젝션이 완료될때 까지 유지
  • 낙관적 동시성 제어 (Optimistic Concurrency Control)
    • 사용자들이 같은 데이터를 동시에 수정하지 않을 것이라고 가정
    • 데이터를 읽을때 Lock을 설정 하지 않음
    • 낙관적 동시성 제어를 사용하면 lock을 유지하는 시간이 매우 짧아져져 동시성이 높아짐


(1) 비관적 동시성 제어

SQL> create table cuspoint as select '5' as no,'1000' as point from dual;

tx1

tx2
 SQL> select point from cuspoint where no=5 for update;

POIN
----
1000
t1


t2
SQL> select * from cuspoint where no='5';

N POIN
- ----
5 1000



t3
SQL> update cuspoint set point=point+1000 where no='5';


SQL>  update cuspoint set point=point+1000 where no='5';

1 row updated.
t4


SQL> commit;

Commit complete.


t5

1 row updated.



t6
SQL> SQL>  select * from cuspoint where no='5';

N POIN
- ----
5 3000




  • for update을 사용하여 해당 고객 레코드에 Lock 을 걸어둔후  tx1세션 종료후 tx2의 세션 수행



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


tx1

tx2
SQL>  select point from cuspoint where no=5
for update nowait;

POIN
----
2000


t1


t2

SQL>  select point from cuspoint where no=5
for update nowait;

 select point from cuspoint where no=5 for update nowait
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified


SQL>



SQL> commit;

Commit complete.


t3





(2) 낙관적 동시성 제어





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
    alert ('다른사용자에 의해 변경되었습니다.');
end if;


  • 컬럼이 많을 경우 별도의 수정일시 제어 컬럼을 뒤고 where 절에 사용하여 판단할수도 있음
  • 개발자가 애플리케이션 구현시 일일이 채크할수 있도록 변경해야함
  • 쿼리툴등을 통해 직업수행시 lost update등의 문제가 생길수 있음

  • 오라클 10g에서는 Pseudo 컬럼 ora_rowscn을 사용하여 관리 가능



ora_rowscn 

  • 오라클 default table 생성 / NoRowDependencies


tx1

tx2
SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796751 06-JUN-10 03.56.52.000000000 PM
      7499 ALLEN         2796751 06-JUN-10 03.56.52.000000000 PM
      7521 WARD          2796751 06-JUN-10 03.56.52.000000000 PM
      7566 JONES         2796751 06-JUN-10 03.56.52.000000000 PM
      7654 MARTIN        2796751 06-JUN-10 03.56.52.000000000 PM
      7698 BLAKE         2796751 06-JUN-10 03.56.52.000000000 PM
      7782 CLARK         2796751 06-JUN-10 03.56.52.000000000 PM
      7788 SCOTT         2796751 06-JUN-10 03.56.52.000000000 PM
      7839 Kinng         2796751 06-JUN-10 03.56.52.000000000 PM
      7844 TURNER        2796751 06-JUN-10 03.56.52.000000000 PM
      7876 ADAMS         2796751 06-JUN-10 03.56.52.000000000 PM
      7900 JAMES         2796751 06-JUN-10 03.56.52.000000000 PM
      7902 FORD          2796751 06-JUN-10 03.56.52.000000000 PM
      7934 MILLER        2796751 06-JUN-10 03.56.52.000000000 PM

14 rows selected.

SQL>


t1
SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
 from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796751 06-JUN-10 03.56.52.000000000 PM
      7499 ALLEN         2796751 06-JUN-10 03.56.52.000000000 PM
      7521 WARD          2796751 06-JUN-10 03.56.52.000000000 PM
      7566 JONES         2796751 06-JUN-10 03.56.52.000000000 PM
      7654 MARTIN        2796751 06-JUN-10 03.56.52.000000000 PM
      7698 BLAKE         2796751 06-JUN-10 03.56.52.000000000 PM
      7782 CLARK         2796751 06-JUN-10 03.56.52.000000000 PM
      7788 SCOTT         2796751 06-JUN-10 03.56.52.000000000 PM
      7839 Kinng         2796751 06-JUN-10 03.56.52.000000000 PM
      7844 TURNER        2796751 06-JUN-10 03.56.52.000000000 PM
      7876 ADAMS         2796751 06-JUN-10 03.56.52.000000000 PM
      7900 JAMES         2796751 06-JUN-10 03.56.52.000000000 PM
      7902 FORD          2796751 06-JUN-10 03.56.52.000000000 PM
      7934 MILLER        2796751 06-JUN-10 03.56.52.000000000 PM

14 rows selected.

SQL>



t2

SQL> update emp set ename='KING' where empno='7876';

1 row updated.


SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796831 06-JUN-10 04.00.40.000000000 PM
      7499 ALLEN         2796831 06-JUN-10 04.00.40.000000000 PM
      7521 WARD          2796831 06-JUN-10 04.00.40.000000000 PM
      7566 JONES         2796831 06-JUN-10 04.00.40.000000000 PM
      7654 MARTIN        2796831 06-JUN-10 04.00.40.000000000 PM
      7698 BLAKE         2796831 06-JUN-10 04.00.40.000000000 PM
      7782 CLARK         2796831 06-JUN-10 04.00.40.000000000 PM
      7788 SCOTT         2796831 06-JUN-10 04.00.40.000000000 PM
      7839 Kinng         2796831 06-JUN-10 04.00.40.000000000 PM
      7844 TURNER        2796831 06-JUN-10 04.00.40.000000000 PM
      7876 KING          2796831 06-JUN-10 04.00.40.000000000 PM
      7900 JAMES         2796831 06-JUN-10 04.00.40.000000000 PM
      7902 FORD          2796831 06-JUN-10 04.00.40.000000000 PM
      7934 MILLER        2796831 06-JUN-10 04.00.40.000000000 PM

14 rows selected.

SQL>


t3


  • tx1에서 scn 이 2796751이었어나 tx2에서 update 완료후 2796831
  • ora_rowscn 을 where 절에서 사용하여 낙관적 동시성 제어 수행 가능



  • rowdependences : 테이블 생성시 row단위로 scn 을 처리


SQL> create table t
rowdependences
nologging
as
select * from emp;


SQL> update t set ename='Kinng' where empno='7839';

SQL> commit;

Commit complete.

SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN) from t e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)
---------- ---------- ---------- -------------------------------------
      7369 SMITH         2796616 06-JUN-10 03.50.47.000000000 PM
      7499 ALLEN         2796616 06-JUN-10 03.50.47.000000000 PM
      7521 WARD          2796616 06-JUN-10 03.50.47.000000000 PM
      7566 JONES         2796616 06-JUN-10 03.50.47.000000000 PM
      7654 MARTIN        2796616 06-JUN-10 03.50.47.000000000 PM
      7698 BLAKE         2796616 06-JUN-10 03.50.47.000000000 PM
      7782 CLARK         2796616 06-JUN-10 03.50.47.000000000 PM
      7788 SCOTT         2796616 06-JUN-10 03.50.47.000000000 PM
      7839 Kinng         2796737 06-JUN-10 03.56.13.000000000 PM
      7844 TURNER        2796616 06-JUN-10 03.50.47.000000000 PM
      7876 ADAMS         2796616 06-JUN-10 03.50.47.000000000 PM

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)
---------- ---------- ---------- ------------------------------------------
      7900 JAMES         2796616 06-JUN-10 03.50.47.000000000 PM
      7902 FORD          2796616 06-JUN-10 03.50.47.000000000 PM
      7934 MILLER        2796616 06-JUN-10 03.50.47.000000000 PM

14 rows selected.

SQL>



  • 참고) ora_rowscn  은 smon 프로세스가 관리하는 scn과 timestamp 매핑테이블에 영향을 받으며
    매핑테이블 갱신주기는 5일 (= scn으로 timestamp 를 확인할수 있는 시기는 5일)





참고 :


Thread: SELECT FOR UPDATE NOWAIT | WAIT 기능 소개
http://forums.oracle.com/forums/thread.jspa?threadID=471919&tstart=208