본문 바로가기
Programming/SQL

[Oracle] 14. 트랜잭션과 잠금(Exclusive Lock, Share Lock, Dead Lock, Undo Segment)

by 고막고막 2019. 4. 26.

트랜잭션(Transaction)

반드시 함께 실행되어야 하는 작업의 단위를 의미. 즉 사용자의 의도에 따라 여러 개의 문장으로 구성된 트랜잭션은 반드시 동시에 실행(COMMIT;)되거나 취소(ROLLBACK;)된다. RDBMS는 트랜잭션을 통해 작업의 단위를 결정함으로써 작업 결과의 신뢰성을 확보한다. 트랜잭션의 기본 과정은 다음과 같다.

1. DML(insert, update, delete), DDL(create, alter, drop, truncate), DCL(grant, revoke)문 실행 
2. 입력된 행에 잠금이 걸림
3. COMMIT 또는 ROLLBACK 실행
4. 잠금 풀림

언두 세그먼트(Undo Segment)

DML 작업이 발생할 때 그 작업을 취소(ROLLBACK;)시키기 위해서는 이전의 데이터를 어딘가에 저장해두어야 한다. 그렇지 않으면 ROLLBACK을 실행할 수 없으므로, 이전 데이터를 저장하는 것은 트랜잭션의 기본 기능이라고 할 수 있겠다. 이러한 물리적 공간을 오라클에서는 Undo Tablespace 와 Undo Segment라는 구조를 사용한다.

독점 잠금(Exclusive Lock) & 공유 잠금(Share Lock)

현재 세션이 작업 중인 에 대해 'Exclusive Lock'이 발생한다. 이는 다른 세션에서는 해당 행을 검색할 수 없고, 단지 Undo segment 의 정보만 보게 된다. 그리고 이와 동시에 해당 행이 포함된 테이블에 대해서  DDL(alter, drop, truncate) 작업을 방지하는 'Share Lock'이 발생한다. 참고로 오라클은 행마다 'Exclusive Lock'을 걸지만 MSSQL 은 I/O 단위인 페이지 전체에 건다.

[세션 1]

// 1)마초의 전공을 사회학과로 변경한다.
UPDATE student SET major='사회' WHERE sname='마초';

// 2)갱신된 마초의 학과를 확인한다. 아직 커밋은 하지 않았다.
SELECT sno, sname, major
FROM student
WHERE sname='마초';

// 5) 아직 세션1의 커밋이 완료되기 전에 세션2가 마초의 학과의 갱신을 시도했다. 
//	  이때 이미 세션1에 의해 독점잠금이 되어있으므로 상대인 세션2는 대기 상태에 들어가게 된다.
COMMIT;

// 6) 세션1이 변경한 사회가 잘 보인다
SELECT sno, sname, major
FROM student
WHERE sname='마초';

[세션 2]

// 3) 마초의 학과를 검색한다. 세션1에서 학과를 '사회'로 변경하였지만,
//	  커밋을 하지 않았기 때문에 세션2는 이전의 정보인 '화학'으로 보여지게 된다.
SELECT sno, sname, major
FROM student
WHERE sname='마초';

// 4)세션1이 독점잠금을 걸어놓은 상태에서 세션2가 학과를 '경제'로 변경을 시도한다. 
//	이미 세션1에 의해 독점 잠금이 되어있으므로 상대인 세션2는 대기 상태에 진입한다.
UPDATE student SET major='경제' WHERE sname='마초';

// 7) 세션1이 커밋하였으므로 대기가 풀려 경제로 갱신이 가능해졌다.
//   하지만 아직 커밋은 완료되지않은 상태임으로 undo segment에서 데이터를 가져오게 된다.
//   그리고 세션2는 마초의 행에 독점 잠금을 걸어놓은 상태이다.
SELECT sno, sname, major
FROM student
WHERE sname='마초';

교착 상태, 데드 락(Dead Lock)

여러개의 세션이 자신이 상대가 필요로 하는 리소스를 소유하면서 서로 상대가 소유한 리소스를 기다리고 있는 상황을 말한다. 이러한 상황에서는 계속해서 해제되지 않는 상대방 리소스를 기다리게 되어 결국 영원히 서로를 기다리게 된다. 데드 락에서 빠져나가려면 한쪽 세션에서 ROLLBACK을 실행해야 한다. 이는 자바에서 멀티 쓰레드를 사용할 때 발생하는 동기화(syncronized)문제와 유사하다.

[세션 1]

// 1) 관우와 장각의 학과를 확인한다
SELECT sno, sname, major
FROM student
WHERE sname IN ('관우', '장각');

// 2) 관우의 학과를 경제학과로 갱신한다. 관우의 레코드 행은 독점잠금이 발생되었다
UPDATE student
SET major='경제' 
WHERE sname='관우';

// 5) 세션2에 의해 장각의 레코드 행이 독점 잠금을 걸린 줄을 모르고 관우의 학과를 경제로 바꾸려고 시도한다.
UPDATE student
SET major='사회'
WHERE sname='장각';

[세션 2]

// 3) 장각의 학과를 경제학과로 갱신한다. 장각의 레코드 행에 독점 잠금이 발생한다.
UPDATE student
SET major='경제' 
WHERE sname='장각';

// 4) 세션1이 이미 독점잠금을 걸어놓은 상태인줄 모르고,
//    관우의 학과를 경제로 바꾸려고 시도한다
UPDATE student
SET major='경제' 
WHERE sname='관우';

// 6) 장각은 세션2에서 독점잠금을 걸고있으므로 대기상태가 되어야 하나,
//    이렇게 되면 세션1과 세션2 모두 대기상태가 되어 데드락에 빠지게 된다.
//    이때 현재 세션에 의해 잠겨있는 리소스를 요청한 세션2 트랜잭션을 롤백시킨다. 
//    롤백은 트랜잭션의 모든 과정을 취소하는 것은 아니고 데드락을 발생시킨 문장만 롤백한다.
ROLLBACK;