Reference : 10. Transactions
*GPT 번역 기반으로 내용이 정확하지 않을 수 있습니다.
이 장에서는 트랜잭션을 정의하고 데이터베이스가 트랜잭션을 처리하는 방식을 설명합니다.
이 장은 다음과 같은 섹션들로 구성되어 있습니다:
트랜잭션은 하나 이상의 SQL 문을 포함하는 논리적이고 원자적인 작업 단위입니다.
트랜잭션은 여러 SQL 문을 그룹화하여 모두 커밋(데이터베이스에 적용)되거나 모두 롤백(데이터베이스에서 취소)되도록 합니다. 오라클 데이터베이스는 각 트랜잭션에 트랜잭션 ID라는 고유 식별자를 할당합니다.
모든 오라클 트랜잭션은 ACID 속성으로 알려진 데이터베이스 트랜잭션의 기본 속성을 따릅니다. ACID는 다음의 약어입니다:
트랜잭션의 모든 작업이 수행되거나 전혀 수행되지 않습니다. 부분적인 트랜잭션은 없습니다. 예를 들어, 트랜잭션이 100개의 행을 업데이트하기 시작했지만 시스템이 20개의 업데이트 후에 실패하면 데이터베이스는 이 20개의 행에 대한 변경 사항을 롤백합니다.
트랜잭션은 데이터베이스를 하나의 일관된 상태에서 다른 일관된 상태로 가져갑니다. 예를 들어, 저축 계좌에서 출금하고 당좌 계좌에 입금하는 은행 트랜잭션에서, 오류가 발생해 데이터베이스가 한 계좌만 입금하게 되어서는 안 됩니다. 이는 일관되지 않은 데이터로 이어집니다.
트랜잭션의 효과는 트랜잭션이 커밋될 때까지 다른 트랜잭션에 표시되지 않습니다. 예를 들어, 한 사용자가 hr.employees 테이블을 업데이트하고 있는 동안 다른 사용자가 동시에 수행한 변경 사항을 볼 수 없습니다. 따라서 사용자들에게는 트랜잭션이 직렬로 실행되는 것처럼 보입니다.
커밋된 트랜잭션에 의해 이루어진 변경 사항은 영구적입니다. 트랜잭션이 완료된 후, 데이터베이스는 복구 메커니즘을 통해 트랜잭션의 변경 사항이 손실되지 않도록 보장합니다.
트랜잭션의 사용은 데이터베이스 관리 시스템과 파일 시스템의 차이점 중 하나입니다.
트랜잭션 개념을 설명하기 위해 은행 데이터베이스를 고려해 보겠습니다.
고객이 저축 계좌에서 당좌 계좌로 돈을 이체할 때, 트랜잭션은 세 가지 별도 작업으로 구성되어야 합니다:
오라클 데이터베이스는 두 가지 상황을 허용해야 합니다. 세 가지 SQL 문이 모두 계좌의 균형을 제대로 유지하면 트랜잭션의 효과를 데이터베이스에 적용할 수 있습니다. 그러나 잔고 부족, 잘못된 계좌 번호 또는 하드웨어 오류 등으로 인해 트랜잭션의 하나 또는 두 개의 문이 완료되지 못하면 데이터베이스는 전체 트랜잭션을 롤백하여 모든 계좌의 균형이 정확하도록 해야 합니다.
다음 그림은 은행 트랜잭션을 보여줍니다. 첫 번째 문은 저축 계좌 3209에서 $500를 차감합니다. 두 번째 문은 당좌 계좌 3208에 $500를 추가합니다. 세 번째 문은 트랜잭션 저널에 이체 기록을 삽입합니다. 마지막 문은 트랜잭션을 커밋합니다.
그림 10-1 설명:
"그림 10-1 은행 트랜잭션" 설명
데이터베이스 트랜잭션은 하나 이상의 문으로 구성됩니다.
구체적으로, 트랜잭션은 다음 중 하나로 구성됩니다:
트랜잭션은 시작과 끝이 있습니다.
참조:
트랜잭션은 첫 번째 실행 가능한 SQL 문이 나타날 때 시작됩니다.
실행 가능한 SQL 문은 DML 및 DDL 문과 SET TRANSACTION 문을 포함하여 데이터베이스 인스턴스로 호출을 생성하는 SQL 문입니다.
트랜잭션이 시작되면, 오라클 데이터베이스는 새로운 트랜잭션에 대한 undo 항목을 기록하기 위해 사용 가능한 undo 데이터 세그먼트에 트랜잭션을 할당합니다. undo 세그먼트와 트랜잭션 테이블 슬롯이 할당될 때까지 트랜잭션 ID는 할당되지 않습니다. 이는 첫 번째 DML 문이 실행될 때 발생합니다. 트랜잭션 ID는 트랜잭션에 고유하며 undo 세그먼트 번호, 슬롯 및 일련 번호를 나타냅니다.
다음 예제는 트랜잭션을 시작하기 위해 UPDATE 문을 실행하고 트랜잭션에 대한 세부 정보를 V$TRANSACTION에서 조회합니다:
SQL> UPDATE hr.employees SET salary=salary;
107 rows updated.
SQL> SELECT XID AS "txn id", XIDUSN AS "undo seg", XIDSLOT AS "slot",
2 XIDSQN AS "seq", STATUS AS "txn status"
3 FROM V$TRANSACTION;
txn id undo seg slot seq txn status
---------------- ---------- ---------- ---------- ----------------
0600060037000000 6 6 55 ACTIVE
참조:
트랜잭션은 다음과 같은 상황에서 종료될 수 있습니다:
커밋의 경우, 사용자는 명시적으로 또는 암시적으로 트랜잭션의 변경 사항을 영구적으로 적용하도록 요청합니다. 트랜잭션에 의해 수행된 변경 사항은 트랜잭션이 커밋된 후에만 영구적이며 다른 사용자에게 표시됩니다.
데이터베이스는 각 DDL 문 전후에 암시적으로 COMMIT 문을 실행합니다. 현재 트랜잭션에 DML 문이 포함되어 있으면, 오라클 데이터베이스는 먼저 트랜잭션을 커밋한 다음 DDL 문을 실행하고 이를 새로운 단일 문 트랜잭션으로 커밋합니다.
참고: 애플리케이션은 프로그램 종료 전에 항상 명시적으로 트랜잭션을 커밋하거나 롤백해야 합니다.
한 트랜잭션이 종료되면, 다음 실행 가능한 SQL 문이 자동으로 다음 트랜잭션을 시작합니다. 다음 예제는 트랜잭션을 시작하기 위해 UPDATE 문을 실행하고 ROLLBACK 문으로 트랜잭션을 종료한 다음 UPDATE 문을 실행하여 새로운 트랜잭션을 시작합니다(트랜잭션 ID가 다름):
SQL> UPDATE hr.employees SET salary=salary;
107 rows updated.
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
XID STATUS
---------------- ----------------
0800090033000000 ACTIVE
SQL> ROLLBACK;
Rollback complete.
SQL> SELECT XID FROM V$TRANSACTION;
no rows selected
SQL> UPDATE hr.employees SET last_name=last_name;
107 rows updated.
SQL> SELECT XID, STATUS FROM V$TRANSACTION;
XID STATUS
---------------- ----------------
0900050033000000 ACTIVE
참조:
밋으로 종료되는 트랜잭션의 예제를 확인하십시오.
오라클 데이터베이스는 문 수준 원자성을 지원합니다. 이는 SQL 문이 작업의 원자적 단위이며 완전히 성공하거나 완전히 실패한다는 것을 의미합니다.
성공적인 문은 커밋된 트랜잭션과 다릅니다. 단일 SQL 문이 성공적으로 실행되면 데이터베이스가 이를 분석하고 원자 단위로 오류 없이 실행합니다. 예를 들어, 다중 행 업데이트에서 모든 행이 변경된 경우입니다.
SQL 문이 실행 중 오류를 일으키면 성공하지 못하며 따라서 문에 대한 모든 효과가 롤백됩니다. 이 작업은 문 수준 롤백입니다. 이 작업은 다음과 같은 특성을 가집니다:
중복 기본 키를 삽입하려고 시도하는 오류는 문 수준 롤백을 일으키는 오류의 예입니다. 동일한 데이터를 경쟁하는 데드락에 관련된 단일 SQL 문도 문 수준 롤백을 일으킬 수 있습니다. 그러나 SQL 문 분석 중에 발견된 오류(예: 구문 오류)는 아직 실행되지 않았으므로 문 수준 롤백을 일으키지 않습니다.
참조:
시스템 변경 번호(SCN)는 오라클 데이터베이스에서 사용되는 논리적이고 내부적인 타임스탬프입니다.
SCN은 데이터베이스 내에서 발생하는 이벤트를 순서대로 정리하여 트랜잭션의 ACID 속성을 만족시킵니다. 오라클 데이터베이스는 SCN을 사용하여 모든 변경 사항이 디스크에 기록된 시점을 표시하여 복구 시 불필요한 리두 적용을 피할 수 있습니다. 데이터베이스는 SCN을 사용하여 데이터 집합에 대해 리두가 없는 시점을 표시하여 복구가 중단될 수 있도록 합니다.
SCN은 단조롭게 증가하는 시퀀스로 발생합니다. 오라클 데이터베이스는 SCN을 시계처럼 사용할 수 있습니다. 관찰된 SCN은 논리적인 시점을 나타내며, 반복적인 관찰은 동일하거나 더 큰 값을 반환합니다. 한 이벤트가 다른 이벤트보다 낮은 SCN을 가지고 있으면, 이는 데이터베이스에서 더 이른 시점에 발생했음을 나타냅니다. 여러 이벤트가 동일한 SCN을 가질 수 있으며, 이는 데이터베이스에서 동일한 시점에 발생했음을 의미합니다.
모든 트랜잭션에는 SCN이 있습니다. 예를 들어, 트랜잭션이 행을 업데이트하면 데이터베이스는 이 업데이트가 발생한 SCN을 기록합니다. 이 트랜잭션의 다른 수정 사항들도 동일한 SCN을 가집니다. 트랜잭션이 커밋되면 데이터베이스는 이 커밋에 대한 SCN을 기록합니다.
오라클 데이터베이스는 시스템 글로벌 영역(SGA)에서 SCN을 증가시킵니다. 트랜잭션이 데이터를 수정하면, 데이터베이스는 트랜잭션에 할당된 undo 데이터 세그먼트에 새로운 SCN을 기록합니다. 로그 라이터 프로세스는 트랜잭션의 커밋 기록을 즉시 온라인 리두 로그에 씁니다. 커밋 기록은 트랜잭션의 고유한 SCN을 가집니다. 오라클 데이터베이스는 인스턴스 복구 및 미디어 복구 메커니즘의 일부로 SCN을 사용합니다.
참조:
트랜잭션 제어는 DML 문에 의해 이루어진 변경 사항의 관리와 DML 문을 트랜잭션으로 그룹화하는 것을 의미합니다.
일반적으로 애플리케이션 설계자는 작업을 논리적 단위로 수행하고 데이터를 일관되게 유지하기 위해 트랜잭션 제어에 관심을 가집니다.
트랜잭션 제어는 "트랜잭션 제어 문"에서 설명된 다음 문을 사용하는 것을 포함합니다:
다음 표 10-1은 트랜잭션 제어의 기본 개념을 설명합니다.
T | 세션 | 설명 |
---|---|---|
t0 | COMMIT; | 이 문은 세션에서 기존 트랜잭션을 종료합니다. |
t1 | SET TRANSACTION NAME 'sal_update'; | 이 문은 트랜잭션을 시작하고 이름을 'sal_update'로 지정합니다. |
t2 | UPDATE employees SET salary = 7000 WHERE last_name = 'Banda'; | 이 문은 Banda의 급여를 7000으로 업데이트합니다. |
t3 | SAVEPOINT after_banda_sal; | 이 문은 'after_banda_sal'이라는 저장점을 생성하여 이 트랜잭션에서 이 지점으로 롤백할 수 있게 합니다. |
t4 | UPDATE employees SET salary = 12000 WHERE last_name = 'Greene'; | 이 문은 Greene의 급여를 12000으로 업데이트합니다. |
t5 | SAVEPOINT after_greene_sal; | 이 문은 'after_greene_sal'이라는 저장점을 생성하여 이 트랜잭션에서 이 지점으로 롤백할 수 있게 합니다. |
t6 | ROLLBACK TO SAVEPOINT after_banda_sal; | 이 문은 트랜잭션을 t3으로 롤백하여 t4의 Greene 급여 업데이트를 취소합니다. 'sal_update' 트랜잭션은 종료되지 않았습니다. |
t7 | UPDATE employees SET salary = 11000 WHERE last_name = 'Greene'; | 이 문은 'sal_update' 트랜잭션에서 Greene의 급여를 11000으로 업데이트합니다. |
t8 | ROLLBACK; | 이 문은 'sal_update' 트랜잭션의 모든 변경 사항을 롤백하여 트랜잭션을 종료합니다. |
t9 | SET TRANSACTION NAME 'sal_update2'; | 이 문은 세션에서 새 트랜잭션을 시작하고 이름을 'sal_update2'로 지정합니다. |
t10 | UPDATE employees SET salary = 7050 WHERE last_name = 'Banda'; | 이 문은 Banda의 급여를 7050으로 업데이트합니다. |
t11 | UPDATE employees SET salary = 10950 WHERE last_name = 'Greene'; | 이 문은 Greene의 급여를 10950으로 업데이트합니다. |
t12 | COMMIT; | 이 문은 'sal_update2' 트랜잭션에서 이루어진 모든 변경 사항을 커밋하여 트랜잭션을 종료합니다. 이 커밋은 변경 사항이 온라인 리두 로그 파일에 저장됨을 보장합니다. |
참조:
트랜잭션 이름은 트랜잭션이 수행하는 작업을 상기시키는 선택적 사용자 지정 태그입니다. 트랜잭션 이름은 SET TRANSACTION ... NAME 문을 사용하여 지정하며, 사용 시 트랜잭션의 첫 번째 문이어야 합니다.
표 10-1에서 첫 번째 트랜잭션은 'sal_update'로, 두 번째는 'sal_update2'로 명명되었습니다.
트랜잭션 이름은 다음과 같은 이점을 제공합니다:
참조:
활성 트랜잭션은 시작되었지만 아직 커밋되거나 롤백되지 않은 트랜잭션입니다.
표 10-1에서 'sal_update' 트랜잭션의 데이터를 수정하는 첫 번째 문은 Banda의 급여를 업데이트하는 것입니다. 이 업데이트가 성공적으로 실행된 시점부터 ROLLBACK 문이 트랜잭션을 종료할 때까지 'sal_update' 트랜잭션은 활성 상태입니다.
트랜잭션에 의해 이루어진 데이터 변경 사항은 트랜잭션이 커밋되거나 롤백될 때까지 일시적입니다. 트랜잭션이 종료되기 전 데이터의 상태는 다음 표와 같습니다.
상태 | 설명 | 자세히 알아보기 |
---|---|---|
Oracle Database가 SGA에 undo 정보를 생성했습니다. | undo 데이터는 트랜잭션의 SQL 문에 의해 변경된 이전 데이터 값을 포함합니다. | "커밋된 읽기 격리 수준의 읽기 일관성" |
Oracle Database가 SGA의 온라인 리두 로그 버퍼에 리두를 생성했습니다. | 리두 로그 기록은 데이터 블록에 대한 변경 사항과 undo 블록에 대한 변경 사항을 포함합니다. | "리두 로그 버퍼" |
데이터베이스 버퍼의 SGA에 변경 사항이 적용되었습니다. | 커밋된 트랜잭션의 데이터 변경 사항은 SGA의 데이터베이스 버퍼에 저장되며, DBW에 의해 데이터 파일에 즉시 기록되지 않을 수 있습니다. 디스크 기록은 커밋 전후에 발생할 수 있습니다. | "데이터베이스 버퍼 캐시" |
데이터 변경에 영향을 받은 행이 잠겨 있습니다. | 다른 사용자는 영향을 받은 행의 데이터를 변경할 수 없으며, 커밋되지 않은 변경 사항을 볼 수 없습니다. | "잠금 동작 요약" |
저장점은 트랜잭션의 컨텍스트 내에서 사용자 정의 중간 마커입니다.
내부적으로 저장점 마커는 SCN으로 해결됩니다. 저장점은 긴 트랜잭션을 더 작은 부분으로 나눕니다.
긴 트랜잭션에서 저장점을 사용하면 트랜잭션 내에서 선언된 저장점 이후의 작업만 롤백할 수 있습니다. 따라서 오류가 발생하더라도 모든 문을 다시 제출할 필요가 없습니다. 표 10-1은 'after_banda_sal' 저장점을 생성하여 Greene 급여 업데이트를 이 저장점으로 롤백할 수 있게 합니다.
커밋되지 않은 트랜잭션에서 저장점으로 롤백하는 것은 지정된 저장점 이후에 이루어진 변경 사항만 취소하는 것을 의미하며, 트랜잭션 자체를 롤백하는 것은 아닙니다.
트랜잭션이 저장점으로 롤백될 때, 예를 들어 표 10-1에서 ROLLBACK TO SAVEPOINT after_banda_sal이 실행될 때 다음이 발생합니다:
백하지 않습니다.
참조:
상황에 따라 이전에 잠긴 리소스를 기다리는 트랜잭션은 저장점으로 롤백한 후에도 여전히 차단될 수 있습니다.
트랜잭션이 다른 트랜잭션에 의해 차단될 때 차단된 트랜잭션 자체에 대기하므로 차단된 트랜잭션은 차단된 트랜잭션이 커밋되거나 롤백될 때까지 계속됩니다.
다음 표에서 보여지는 시나리오에서 세션 1은 DML 문을 실행하기 전에 생성된 저장점으로 롤백합니다. 그러나 세션 2는 세션 1 트랜잭션이 완료되기를 기다리고 있으므로 여전히 차단된 상태입니다.
T | 세션 1 | 세션 2 | 세션 3 | 설명 |
---|---|---|---|---|
t0 | UPDATE employees SET salary=7000 WHERE last_name='Banda'; | 세션 1이 트랜잭션을 시작합니다. 세션은 Banda 행(TX)에 대해 배타적 잠금과 테이블에 대해 하위 배타적 잠금(SX)을 설정합니다. | ||
t1 | SAVEPOINT after_banda_sal; | 세션 1이 after_banda_sal이라는 저장점을 생성합니다. | ||
t2 | UPDATE employees SET salary=12000 WHERE last_name='Greene'; | 세션 1이 Greene 행을 잠급니다. | ||
t3 | UPDATE employees SET salary=14000 WHERE last_name='Greene'; | 세션 2가 Greene 행을 업데이트하려고 시도하지만 세션 1이 이 행을 잠가서 잠금을 획득하지 못합니다. 세션 2에서는 트랜잭션이 시작되지 않았습니다. | ||
t4 | ROLLBACK TO SAVEPOINT after_banda_sal; | 세션 1이 Greene의 급여 업데이트를 롤백하여 Greene의 행 잠금을 해제합니다. t0에서 획득한 테이블 잠금은 해제되지 않습니다. 세션 2는 여전히 세션 1에 의해 차단됩니다. | ||
t5 | UPDATE employees SET salary=11000 WHERE last_name='Greene'; | Greene 행이 현재 잠겨 있지 않으므로 세션 3이 Greene 행을 업데이트하기 위해 잠금을 획득합니다. 이 문은 세션 3에서 트랜잭션을 시작합니다. | ||
t6 | COMMIT; | 세션 1이 커밋하여 트랜잭션을 종료합니다. 세션 2는 이제 세션 3의 트랜잭션 뒤에 Greene 행에 대한 업데이트를 대기하게 됩니다. |
참조:
커밋되지 않은 트랜잭션의 롤백은 트랜잭션 내에서 SQL 문에 의해 수행된 데이터에 대한 모든 변경 사항을 취소합니다.
트랜잭션이 롤백된 후 트랜잭션에서 수행된 작업의 효과는 더 이상 존재하지 않습니다. 참조된 저장점 없이 전체 트랜잭션을 롤백할 때, Oracle Database는 다음 작업을 수행합니다:
활성 트랜잭션에 대한 트랜잭션 테이블 항목에는 트랜잭션의 모든 undo 데이터(적용 순서의 역순)에 대한 포인터가 포함되어 있습니다. 데이터베이스는 undo 세그먼트에서 데이터를 읽고 작업을 반대로 적용한 다음 undo 항목을 적용된 것으로 표시합니다. 따라서 트랜잭션이 행을 삽입하면 롤백은 이를 삭제합니다. 트랜잭션이 행을 업데이트하면 롤백은 업데이트를 취소합니다. 트랜잭션이 행을 삭제하면 롤백은 이를 다시 삽입합니다. 표 10-1에서 ROLLBACK은 Greene과 Banda의 급여에 대한 업데이트를 취소합니다.
표 10-1에서 ROLLBACK은 after_banda_sal 저장점을 삭제합니다. after_greene_sal 저장점은 ROLLBACK TO SAVEPOINT 문에 의해 제거되었습니다.
표 10-1에서 ROLLBACK은 초기 COMMIT이 실행된 후 데이터베이스를 동일한 상태로 남깁니다.
롤백의 지속 시간은 수정된 데이터 양의 함수입니다.
참조:
커밋은 현재 트랜잭션을 종료하고 트랜잭션에서 수행된 모든 변경 사항을 영구적으로 만듭니다.
표 10-1에서 두 번째 트랜잭션은 sal_update2로 시작하여 명시적인 COMMIT 문으로 종료됩니다. 두 개의 UPDATE 문에서 발생한 변경 사항이 이제 영구적으로 적용되었습니다.
트랜잭션이 커밋되면 다음 작업이 발생합니다:
표 10-1에서 sal_update 트랜잭션에는 저장점이 없었으므로 삭제된 저장점도 없습니다.
커밋된 트랜잭션의 데이터를 포함하는 수정된 블록이 아직 SGA에 있으며 다른 세션이 이를 수정하지 않는 경우, 데이터베이스는 블록에서 잠금 관련 트랜잭션 정보를 제거합니다(ITL 항목).
이상적으로, COMMIT은 후속 SELECT가 이 작업을 수행할 필요가 없도록 블록을 정리합니다. 특정 행에 대해 ITL 항목이 없는 경우, 이는 잠겨 있지 않음을 의미합니다. 특정 행에 대해 ITL 항목이 있는 경우, 이는 잠겨 있을 가능성이 있으므로 세션은 해당 관심 트랜잭션이 커밋되었는지 확인하기 위해 undo 세그먼트 헤더를 확인해야 합니다. 관심 트랜잭션이 커밋된 경우, 세션은 블록을 정리하여 리두를 생성합니다. 그러나 COMMIT이 이전에 ITL을 정리한 경우, 확인 및 정리 작업이 불필요합니다.
참고: 블록 정리는 리두를 생성하므로 쿼리는 리두를 생성할 수 있으며 다음 체크포인트 동안 블록을 쓰게 할 수 있습니다.
Oracle Database는 트랜잭션을 완료로 표시합니다.
트랜잭션이 커밋된 후 사용자는 변경 사항을 볼 수 있습니다.
일반적으로 커밋은 트랜잭션 크기에 관계없이 빠른 작업입니다. 커밋 속도는 트랜잭션에서 수정된 데이터 양에 비례하지 않습니다. 커밋의 가장 긴 부분은 LGWR에 의해 수행되는 물리적 디스크 I/O입니다. 그러나 LGWR은 백그라운드에서 리두 로그 버
퍼의 내용을 점진적으로 작성했기 때문에 소요 시간이 줄어듭니다.
기본 동작은 LGWR이 리두를 온라인 리두 로그에 동기적으로 작성하고 트랜잭션이 버퍼된 리두가 디스크에 기록되기를 기다렸다가 사용자에게 커밋을 반환하는 것입니다. 그러나 트랜잭션 커밋 지연을 줄이기 위해 애플리케이션 개발자는 리두를 비동기적으로 작성하도록 지정하여 트랜잭션이 리두가 디스크에 기록될 때까지 기다릴 필요 없이 즉시 COMMIT 호출에서 반환할 수 있습니다.
참조:
트랜잭션 가드는 트랜잭션의 아이드포턴스를 제공하기 위해 애플리케이션이 사용할 수 있는 API입니다. 이는 트랜잭션이 커밋되고 완료되었는지 여부를 나타내는 보장된 커밋 결과를 데이터베이스가 보존할 수 있게 합니다. Oracle Database는 JDBC thin, OCI, OCCI, ODP.Net에 대한 API를 제공합니다.
복구 가능한 오류는 애플리케이션 세션 논리와 무관한 외부 시스템 실패로 인해 발생합니다. 복구 가능한 오류는 포그라운드 프로세스, 네트워크, 노드, 스토리지 및 데이터베이스의 계획되거나 계획되지 않은 중단 이후에 발생합니다. 중단이 클라이언트 애플리케이션과 데이터베이스 간의 연결을 끊으면 애플리케이션은 연결 끊김 오류 메시지를 받습니다. 연결이 끊겼을 때 실행 중이던 트랜잭션을 인플라이트 트랜잭션이라고 합니다.
트랜잭션을 다시 제출할지 또는 클라이언트에게 결과(커밋되었는지 여부)를 반환할지 결정하려면 애플리케이션이 인플라이트 트랜잭션의 결과를 확인해야 합니다. Oracle Database 12c 이전에는 클라이언트에게 반환된 커밋 메시지가 지속되지 않았습니다. 트랜잭션을 확인해도 확인 후 커밋되지 않는다는 보장이 없었기 때문에 중복 트랜잭션 및 기타 논리적 손상이 발생할 수 있었습니다. 예를 들어, 사용자가 온라인으로 책을 구매할 때 웹 브라우저를 새로 고침하면 같은 책에 대해 두 번 청구될 수 있습니다.
참조:
Oracle Database 12c부터 트랜잭션 가드는 복구 가능한 중단 후 인플라이트 트랜잭션의 상태를 결정하기 위한 도구를 애플리케이션에 제공합니다.
트랜잭션 가드를 사용하면 애플리케이션이 트랜잭션을 한 번만 실행하도록 보장할 수 있습니다. 예를 들어, 온라인 서점 애플리케이션에서 이전에 제출된 커밋이 실패한 것으로 확인되면 애플리케이션은 안전하게 다시 제출할 수 있습니다.
트랜잭션 가드는 애플리케이션이 중복 제출을 실행하지 않도록 하기 위해 한 번만 실행되는 도구를 제공합니다. 트랜잭션 가드는 모든 트랜잭션에 대해 알려진 결과를 제공합니다.
트랜잭션 가드는 핵심 Oracle Database 기능입니다. 애플리케이션 연속성은 중단을 최종 사용자에게 마스킹할 때 트랜잭션 가드를 사용합니다. 트랜잭션 가드가 없으면 오류 후 다시 시도하는 애플리케이션이 중복 트랜잭션을 커밋할 수 있습니다.
참조:
이 섹션에서는 커밋 메시지 손실 문제와 트랜잭션 가드가 논리적 트랜잭션 ID를 사용하여 문제를 해결하는 방법을 설명합니다.
아이드포턴스를 설계할 때 개발자는 커밋 문 제출 후 통신 장애 문제를 해결해야 합니다. 커밋 메시지는 데이터베이스에 지속되지 않으므로 실패 후 검색할 수 없습니다.
다음 그래픽은 클라이언트 애플리케이션과 데이터베이스 간의 상호 작용을 고수준으로 나타냅니다.
그림 10-2 설명:
"그림 10-2 커밋 메시지 손실" 설명
표준 커밋 사례에서는 데이터베이스가 트랜잭션을 커밋하고 클라이언트에 성공 메시지를 반환합니다. 그림 10-2에서 클라이언트는 커밋 문을 제출하고 통신 실패를 알리는 메시지를 받습니다. 이러한 유형의 실패는 데이터베이스 인스턴스 실패나 네트워크 중단 등 여러 가지 이유로 발생할 수 있습니다. 이 시나리오에서는 클라이언트가 트랜잭션 상태를 알 수 없습니다.
통신 장애 후에도 데이터베이스는 여전히 제출을 실행 중이며 클라이언트가 연결이 끊긴 사실을 인식하지 못할 수 있습니다. 트랜잭션 상태를 확인해도 확인 후 활성 트랜잭션이 커밋되지 않을 것이라는 보장이 없습니다. 클라이언트가 이 오래된 정보 때문에 커밋을 다시 보내면 데이터베이스가 트랜잭션을 반복하여 논리적 손상이 발생할 수 있습니다.
Oracle Database는 논리적 트랜잭션 ID라는 전역 고유 식별자를 사용하여 통신 장애를 해결합니다.
이 ID는 세션이 처음 연결될 때 할당된 논리적 세션 번호와 세션이 커밋되거나 롤백될 때마다 업데이트되는 실행 중인 커밋 번호를 포함합니다. 애플리케이션 관점에서 논리적 트랜잭션 ID는 실패한 세션에서 제출된 마지막 데이터베이스 트랜잭션을 고유하게 식별합니다.
클라이언트에서 한 번 이상의 트랜잭션이 커밋되는 각 왕복 요청에 대해 데이터베이스는 논리적 트랜잭션 ID를 저장합니다. 이 ID는 애플리케이션과 데이터베이스 간의 상호 작용에 대해 데이터를 커밋하는 각 왕복 요청에 대해 트랜잭션 아이드포턴스를 제공합니다.
한 번만 실행되는 프로토콜은 데이터베이스가 다음을 수행하도록 요구하여 커밋 결과에 액세스할 수 있게 합니다:
트랜잭션이 실행되는 동안 데이터베이스와 클라이언트 모두 논리적 트랜잭션 ID를 보유합니다. 데이터베이스는 클라이언트가 하나 이상의 커밋 작업을 실행하는 각 왕복 요청 시 클라이언트에 논리적 트랜잭션 ID를 제공합니다.
애플리케이션이 복구 가능한 오류 후 마지막 트랜잭션의 결과를 결정하기 전에 애플리케이션은 Java, OCI, OCCI 또는 ODP.Net API를 사용하여 클라이언트에서 보유한 논리적 트랜잭션 ID를 얻습니다. 그런 다음 애플리케이션은 논리적 트랜잭션 ID로 PL/SQL 절차 DBMS_APP_CONT.GET_LTXID_OUTCOME을 호출하여 마지막 제출 결과를 결정합니다: 커밋됨(참 또는 거짓) 및 사용자 호출 완료(참 또는 거짓).
트랜잭션 가드를 사용할 때, 애플리케이션은 오류가 복구 가능하고 세션의 마지막 트랜잭션이 커밋되지 않은 경우 트랜잭션을 재실행할 수 있습니다. 마지막 트랜잭션이 커밋되고 사용자 호출이 완료되면 애플리케이션은 계속 진행할 수 있습니다. 애플리케이션은 트랜잭션 가드를 사용하여 클라이언트에 알려진 결과를 반환하여 클라이언트가 다음 작업을 결정할 수 있게 합니다.
참조:
이 시나리오에서는 복구 가능한 오류로 인해 커밋 메시지가 손실됩니다.
트랜잭션 가드는 논리적 트랜잭션 ID를 사용하여 COMMIT 문 결과를 보존하여 트랜잭션의 알려진 결과가 있음을 보장합니다.
그림 10-3 설명:
"그림 10-3 논리적 트랜잭션 상태 확인" 설명
그림 10-3에서 데이터베이스는 애플리케이션에 트랜
잭션이 커밋되었는지, 마지막 사용자 호출이 완료되었는지 여부를 알려줍니다. 애플리케이션은 그런 다음 최종 사용자에게 결과를 반환할 수 있습니다. 가능한 결과는 다음과 같습니다:
참조:
애플리케이션 연속성은 계획되지 않거나 계획된 중단 후 불완전한 애플리케이션 요청을 재실행하여 애플리케이션의 중단을 마스킹하려고 시도합니다. 이 문맥에서 요청은 애플리케이션의 작업 단위를 의미합니다.
일반적으로 요청은 단일 데이터베이스 연결에서 단일 웹 요청의 DML 문 및 기타 데이터베이스 호출에 해당합니다. 일반적으로 요청은 연결 풀에서 데이터베이스 연결을 체크아웃하고 체크인하는 사이에 수행된 호출로 구분됩니다.
이 섹션은 다음 주제를 포함합니다:
개발자의 기본 문제는 최종 사용자에게 데이터베이스 세션 손실을 마스킹하는 방법입니다.
애플리케이션 연속성은 데이터베이스와 클라이언트 간의 대화를 방해하는 모든 구성 요소를 복원하여 손실된 세션 문제를 해결하려고 시도합니다. 복원된 데이터베이스 세션에는 모든 상태, 커서, 변수 및 가장 최근의 트랜잭션이 포함됩니다.
일반적인 경우, 클라이언트는 데이터베이스에 요청을 제출했으며, 이로 인해 트랜잭션 상태와 비트랜잭션 상태가 모두 생성되었습니다.
클라이언트의 상태는 입력된 데이터, 반환된 데이터 및 캐시된 데이터와 변수를 포함하여 최신 상태로 유지됩니다. 그러나 애플리케이션이 작동해야 하는 데이터베이스 세션 상태는 손실됩니다.
클라이언트 요청이 하나 이상의 트랜잭션을 시작한 경우, 애플리케이션은 다음과 같은 상황에 직면하게 됩니다:
재실행이 성공하면 계획된 중단 및 계획되지 않은 중단에 대한 데이터베이스 사용자 서비스가 중단되지 않습니다. 데이터베이스가 애플리케이션이 본 데이터의 변경 사항을 감지하고 잠재적으로 작동하는 경우 재실행이 거부됩니다. 재실행을 시작하는 데 허용된 시간이 초과되거나, 애플리케이션이 제한된 호출을 사용하거나, 애플리케이션이 disableReplay 메서드를 사용하여 재실행을 명시적으로 비활성화한 경우에는 재실행이 시도되지 않습니다.
참조:
계획된 중단에 대한 애플리케이션 연속성은 데이터베이스 세션을 신뢰할 수 있게 드레인하거나 마이그레이션할 수 있도록 애플리케이션이 계속 작동할 수 있게 합니다.
예정된 유지 관리는 애플리케이션 작업을 방해할 필요가 없습니다. 애플리케이션 연속성은 현재 유지 관리에 영향을 받지 않는 새로운 위치로 현재 위치에서 활성 작업을 드레인할 시간을 제공합니다. 드레인 간격이 끝나면 세션이 유지 관리가 계획된 데이터베이스 인스턴스에 남아 있을 수 있습니다. 이러한 세션을 강제로 연결 끊기 대신, 애플리케이션 연속성은 이러한 세션을 생존하는 사이트로 페일오버하고 모든 인플라이트 트랜잭션을 다시 제출할 수 있습니다.
애플리케이션 연속성을 사용하면 데이터베이스는 다음을 수행할 수 있습니다:
참조:
애플리케이션 연속성의 주요 구성 요소는 런타임, 재연결 및 재실행입니다.
단계는 다음과 같습니다:
이 단계에서 애플리케이션 연속성은 다음 작업을 수행합니다:
이 단계는 복구 가능한 오류에 의해 트리거됩니다. 애플리케이션 연속성은 다음 작업을 수행합니다:
애플리케이션 연속성은 다음 작업을 수행합니다:
참조:
자율 트랜잭션은 다른 트랜잭션(주 트랜잭션)에서 호출될 수 있는 독립적인 트랜잭션입니다. 호출 트랜잭션을 일시 중지하고 자율 트랜잭션에서 SQL 작업을 수행하고 커밋하거나 롤백한 후 호출 트랜잭션을 재개할 수 있습니다.
자율 트랜잭션은 호출 트랜잭션이 커밋되든 롤백되든 관계없이 독립적으로 수행해야 하는 작업에 유용합니다. 예를 들어, 주식 구매 트랜잭션에서 전체 주식 구매가 진행되지 않더라도 고객 데이터를 커밋하고 싶습니다. 또한 전체 트랜잭션이 롤백되더라도 디버그 테이블에 오류 메시지를 기록하고 싶습니다.
자율 트랜잭션은 다음과 같은 특성을 가지고 있습니다:
PL/SQL에서 자율 트랜잭션은 AUTONOMOUS_TRANSACTION 프래그마로 표시된 루틴 내에서 실행됩니다. 이 문맥에서 루틴에는 최상위 익명 PL/SQL 블록, PL/SQL 하위 프로그램 및 트리거가 포함됩니다. 프래그마는 컴파일러에게 컴파일 옵션을 수행하도록 지시하는 지시문입니다. 프래그마 AUTONOMOUS_TRANSACTION은 데이터베이스에 이 프로시저가 실행될 때 부모 트랜잭션과 독립적인 새로운 자율 트랜잭션으로 실행되도록 지시합니다.
다음 그림은 주 루틴(MT)에서 자율 루틴으로 그리고 다시 돌아오는 제어 흐름을 보여줍니다. 주 루틴은 proc1이고 자율 루틴은 proc2입니다. 자율 루틴은 제어가 주 루틴으로 돌아오기 전에 여러 트랜잭션(AT1 및 AT2)을 커밋할 수 있습니다.
그림 10-4 설명:
"그림 10-4 트랜잭션 제어 흐름" 설명
자율 루틴의 실행 섹션에 들어가면 주 루틴이 일시 중지됩니다. 자율 루틴에서 나가면 주 루틴이 재개됩니다.
그림 10-4에서 proc1 내부의 COMMIT은 자신의 작업뿐만 아니라 세션에서 수행된 모든 미결 작업을 영구적으로 만듭니다. 그러나 proc2 내부의 COMMIT은 proc2 트랜잭션에서 수행된 작업만 영구적으로 만듭니다. 따라서 트랜잭션 AT1 및 AT2의 COMMIT 문은 MT 트랜잭션에 영향을 미치지 않습니다.
참조:
분산 트랜잭션은 데이터베이스 링크라는 스키마 개체를 사용하여 분산 데이터베이스의 두 개 이상의 다른 노드에서 데이터를 업데이트하는 하나 이상의 문을 포함하는 트랜잭션입니다.
분산 데이터베이스는 분산 시스템에서 애플리케이션에 단일 데이터 소스로 나타날 수 있는 데이터베이스 집합입니다. 데이터베이스 링크는 한 데이터베이스 인스턴스가 다른 데이터베이스 인스턴스에 로그인하는 방법을 설명합니다.
로컬 데이터베이스의 트랜잭션과 달리, 분산 트랜잭션은 여러 데이터베이스의 데이터를 변경합니다. 따라서 분산 트랜잭션 처리는 더 복잡합니다. 데이터베이스는 트랜잭션에서 변경 사항을 원자 단위로 커밋하거나 롤백하는 것을 조정해야 합니다. 전체 트랜잭션은 커밋되거나 롤백되어야 합니다. Oracle Database는 네트워크를 통해 트랜잭션 제어를 조정하고 네트워크 또는 시스템 오류가 발생하더라도 데이터 일관성을 유지해야 합니다.
참조:
이페이즈 커밋 메커니즘은 분산 트랜잭션에 참여하는 모든 데이터베이스가 트랜잭션의 모든 문을 모두 커밋하거나 모두 롤백하도록 보장합니다. 이 메커니즘은 무결성 제약 조건, 원격 프로시저 호출 및 트리거에 의해 수행된 암시적 DML도 보호합니다.
여러 데이터베이스 간의 이페이즈 커밋에서 한 데이터베이스가 분산 트랜잭션을 조정합니다. 시작 노드를 글로벌 코디네이터라고 합니다. 코디네이터는 다른 데이터베이스에 커밋 준비 여부를 묻습니다. 어떤 데이터베이스가 아니오라고 응답하면 전체 트랜잭션이 롤백됩니다. 모든 데이터베이스가 예라고 응답하면 코디네이터는 각 데이터베이스에서 커밋을 영구적으로 만드는 메시지를 방송합니다.
이페이즈 커밋 메커니즘은 분산 트랜잭션을 발행하는 사용자에게 투명합니다. 실제로 사용자는 트랜잭션이 분산되었는지조차 알 필요가 없습니다. 트랜잭션의 끝을 나타내는 COMMIT 문은 자동으로 이페이즈 커밋 메커니즘을 트리거합니다. 데이터베이스 애플리케이션 본문에 분산 트랜잭션을 포함하기 위해 복잡한 코딩이나 문법이 필요하지 않습니다.
참조:
의심스러운 분산 트랜잭션은 이페이즈 커밋이 시스템이나 네트워크 오류로 인해 중단된 경우 발생합니다.
예를 들어, 두 개의 데이터베이스가 조정 데이터베이스에 커밋 준비가 되었음을 보고했지만, 조정 데이터베이스 인스턴스가 메시지를 수신한 직후 실패했습니다. 커밋 준비가 된 두 데이터베이스는 결과에 대한 알림을 기다리면서 이제 보류 상태가 됩니다.
복구 프로세스(RECO) 백그라운드 프로세스는 의심스러운 분산 트랜잭션의 결과를 자동으로 해결합니다. 오류가 수정되고 통신이 복구된 후, 각 로컬 Oracle 데이터베이스의 RECO 프로세스는 관련된 모든 노드에서 의심스러운 분산 트랜잭션을 자동으로 커밋하거나 롤백합니다.
장기 오류가 발생한 경우, Oracle Database는 각 로컬 관리자가 오류로 인해 의심스러운 분산 트랜잭션을 수동으로 커밋하거나 취소할 수 있게 합니다. 이 옵션은 장기 오류로 인해 무기한으로 보류 중인 잠금된 리소스를 로컬 데이터베이스 관리자가 해제할 수 있게 합니다.
데이터베이스를 과거 시점으로 복구해야 하는 경우, 데이터베이스 복구 기능을 사용하여 다른 사이트의 데이터베이스 관리자가 데이터베이스를 이전 시점으로 되돌릴 수 있습니다. 이 작업은 글로벌 데이터베이스의 일관성을 보장합니다.
참조:
각주 1:
Oracle Real Application Clusters(Oracle RAC)의 경우, 논리적 트랜잭션 ID는 데이터베이스 인스턴스 번호를 접두사로 포함합니다.