본문 바로가기

Kitri_NCS3기 보안과정/DB보안

170531 트랜잭션(Transaction)

TRANSACTION은 "논리적으로 하나의 단위로 처리되어야 하는 하나 이상의 DML 문장(들)" 입니다. DML의 작업이 이루어지는 과정이라고 생각하면되겠습니다. 트랜잭션은 보통 다른 DB 시스템에선 자동으로 COMMIT이 되서 종료가 되는데 ORACLE의 경우 사용자가 COMMIT을 해줘야 합니다. 


COMMINT / ROLLBACK

COMMIT-문

 DML-문장 완료 후, 변경 후의 데이터 상태를 유지하면서 트랜잭션을 정상적으로 종료합니다.

 ROLLBACK-문

DML-문장 완료 후, 변경 전의 데이터 상태로 되돌려 놓고 트랜잭션을 정상적으로 종료합니다. 


그럼 트랜잭션은 어떻게 종료되느냐 ? 

세션에서 DML 작업 등을 하기위해 서버 프로세스에 붙으면 서버프로세스는 세션에 번호를 부여합니다. 이게 트랜잭션 ID 라고 하는데 이 부여받은 ID는 트랜잭션의 작업이 종료 (COMMIT/ROLLBACK)되면 해제된다고 합니다. COMMIT/ROLLBACK 등으로 종료되기전까지의 DML작업은 모두 하나의 트랜잭션 작업으로 이루어 진다고 하네요. 세번의 DML작업을 하고 COMMIT 이든 ROLLBACK 이든 해버리면 세번의 DML 작업에 모두 적용이 된다는겁니다. 트랜잭션의 아이디를 부여받고 작업을 하고나서 DML 작업을 한 후 COMMIT/ ROLLBACK 문을 사용해서 명시적으로 종료를 해주는게 정석이지만 자동으로 커밋되는 경우가 있습니다. 


자동으로 COMMIT 되는 경우는 DML이 아닌 DDL, DCL 작업을 수행했을 경우는 오라클 서버가 자동으로 COMMIT을 수행합니다. 시스템 권한과 생성에 관련된 내용인 만큼 서버자체가 관리하도록 프로그래밍 되있는것같습니다.

그럼 예를들어 DML에서 COMMIT/ROLLBACK 을 하지 않았을 경우 트랜잭션이 그대로 살아있을겁니다. 이상태에서 DDL이나 DCL 문을 사용하면 이전에 사용한 DML 까지 COMMIT 되게 된다는 겁니다. 정확히 말하면 DDL이나 DCL 작업이 시작되기전에 성질이 다른 작업이 이전에 진행 됫을 경우가 있기 때문에 분리하기위해 COMMIT을 미리 한번 진행한다고 합니다. 그리고 나서 끝날때도 COMMIT 을 하면서 앞뒤로 커밋을 하는모습을 보여준다고 하네요. 결국 이전의 DML을 사용한 트랜잭션과는 분리된 트랜잭션에서 작업이 이루어지겠네요.


트랜잭션이 서버에서 진행중인 경우(DML작업 완료 - COMMIT 하기전)에는 ROLLBACK으로 이전 상태를 복구시킬수도 있고, DML을 수행한 현재 트랜잭션을 할당받은 세션은 SELECT문을 이용해서 수정된 내용을 확인 할 수 있습니다.(외부 다른 세션의 SELECT접근은 이전의 내용을 확인 할 수 있습니다.) 이때 트랜잭션의 상태에서 작업중인 영역은 LOCK 상태가 됩니다.  오라클에선 작업중인 행 (Row)에만 잠금이 걸리지만 다른 DB는 테이블 전체가 잠기는 차이점이 있다고 합니다. 


또 하나 알아야 할 부분은 오라클은 SELECT 문은 트랜잭션으로 관리하지 않습니다. 그렇기 때문에 종료되지 않은 트랜잭션에 의해 LOCK 이 걸린 상태의 행을 참조하는 경우에는 UNDO에 저장된 내용으로 이전에 COMMIT되었던 내용을 보여준다고 하네요 (현재 DML로 수정된 내용은 COMMIT 되기 전까지는 현재 사용중인 세션밖에 확인 할 수 없습니다.)


COMMIT 문이 실행되면 변경한 데이터가 저장이되고 외부 세션의 접근도 변경후의 내용을 확인 할 수 있게됩니다. LOCK이 해제되고 다른 유저가 해당 행에 대해서 DML 작업을 실행할 수 있게됩니다. 

ROLLBACK문의 경우 변경된 데이터의 내용을 취소하고 변경되기 이전의 상태로 복원시키면서 LOCK을 해제합니다.




SELECT 문에서 FOR UPDATE 사용


select문에 의해서 액세스되는 행에 LOCK을 걸수 있습니다. for update를 실행하면 COMMIT/ROLLBACK을 하기 전까지는 다른 세션에 대해 베타적인 상태를 유지하게 됩니다. 


ORDER BY 위에 작성하면됩니다. 마찬가지로 FOR UPDATE로 LOCK을 걸어도 해당하는 행에만 LOCK이 걸리게 됩니다. 

JOIN문의 경우 해당하는 테이블의 모든 행에 LOCK이 걸리게 되며 선택적으로 LOCK을 걸 수 도있는데요 .



파란부분처럼 FOR UPDATE OF 아무컬럼명 을 작성해주면 컬럼이 해당하는 테이블의 행만 LOCK 되고 다른 테이블의 행은 영향을 받지않습니다. 


만약 이미 LOCK 이걸린 상태의 행에다가 FOR UPDATE 를 사용하면 어떻게 될까요 ? 

LOCK 이 풀릴때 까지 정지 상태가 될겁니다. 이런 불편함을 방지하기위해 WAIT 과 NO WAIT 을 사용 할 수 있는데요. 

FOR UPDATE WAIT 5 - 접근하려는 행이 LOCK 상태이면 5초가 지난후 오류 발생후 문장 중지 


FOR UPDATE NO WAIT - 접근하려는 행이 LOCK 상태이면 바로 중지

와 같이 활용 할 수 있습니다.