Session.commitTransaction()
정의
Session.commitTransaction()
다중 문서 트랜잭션 에서 작업으로 인한 변경 사항을 저장하고 트랜잭션 을 종료합니다.
중요
Mongo쉬 방법
이 페이지에서는
mongosh
메서드를 설명합니다. 이는 데이터베이스 명령 또는 Node.js와 같은 언어별 드라이버에 대한 설명서가 아닙니다.데이터베이스 명령에 대해서는
commitTransaction
명령을 참조하십시오.MongoDB API 드라이버의 경우 언어별 MongoDB 드라이버 설명서를 참조하세요.
버전 4.2에서 변경 : MongoDB 4.2부터 샤딩된 클러스터와 복제본 세트 모두에서 다중 문서 트랜잭션을 사용할 수 있습니다.
행동
쓰기 고려
트랜잭션을 커밋할 때 세션은 트랜잭션 시작 시 지정된 쓰기 고려를 사용합니다. Session.startTransaction()
을 참조하세요.
"w: 1"
쓰기 고려를 사용하여 커밋하는 경우 트랜잭션이 페일오버 프로세스 중에 롤백될 수 있습니다.
원자성
트랜잭션이 커밋되면 트랜잭션에서 이루어진 모든 데이터 변경 사항이 저장되고 트랜잭션 외부에서 볼 수 있습니다. 즉, 트랜잭션은 다른 트랜잭션을 롤백하는 동안 다른 변경 사항을 커밋하지 않습니다.
트랜잭션이 커밋될 때까지 트랜잭션에서 변경된 데이터는 트랜잭션 외부에 표시되지 않습니다.
그러나 트랜잭션이 여러 샤드에 쓰기를 수행하는 경우, 모든 외부 읽기 작업이 커밋된 트랜잭션의 결과가 샤드 전체에 표시될 때까지 기다릴 필요는 없습니다. 예를 들어, 트랜잭션이 커밋되고 쓰기 1이 샤드 A에 표시되지만 쓰기 2가 샤드 B에 아직 표시되지 않는 경우, 읽기 고려 "local"
의 외부 읽기는 쓰기 2를 보지 않고 쓰기 1의 결과를 읽을 수 있습니다.
재시도 가능
커밋 작업에 오류가 발생하면 MongoDB 드라이버는 retryWrites
가 false
로 설정되었는지 여부에 관계없이 커밋 작업을 한 번 다시 시도합니다. 자세한 내용은 트랜잭션 오류 처리를 참조하세요.
예시
hr
데이터베이스의 직원 기록이 변경될 때 reporting
데이터베이스의 events
collection이 hr
변경 사항과 동기화되도록 하려는 시나리오를 생각해 보겠습니다. 즉, 이러한 쓰기가 단일 트랜잭션으로 수행되어 두 작업이 모두 성공하거나 실패하도록 해야 합니다.
hr
데이터베이스의 employees
컬렉션에는 다음 문서가 포함되어 있습니다.
{ "_id" : ObjectId("5af0776263426f87dd69319a"), "employee" : 3, "name" : { "title" : "Mr.", "name" : "Iba Ochs" }, "status" : "Active", "department" : "ABC" } { "_id" : ObjectId("5af0776263426f87dd693198"), "employee" : 1, "name" : { "title" : "Miss", "name" : "Ann Thrope" }, "status" : "Active", "department" : "ABC" } { "_id" : ObjectId("5af0776263426f87dd693199"), "employee" : 2, "name" : { "title" : "Mrs.", "name" : "Eppie Delta" }, "status" : "Active", "department" : "XYZ" }
reporting
데이터베이스의 events
컬렉션에는 다음 문서가 포함되어 있습니다.
{ "_id" : ObjectId("5af07daa051d92f02462644a"), "employee" : 1, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } } { "_id" : ObjectId("5af07daa051d92f02462644b"), "employee" : 2, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "XYZ", "old" : null } } { "_id" : ObjectId("5af07daa051d92f02462644c"), "employee" : 3, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
다음 예에서는 트랜잭션을 열고 employees
상태에서 직원의 상태를 Inactive
로 업데이트하고 events
컬렉션에 해당 문서를 삽입하고 두 작업을 단일 트랜잭션으로 커밋합니다.
// Runs the txnFunc and retries if TransientTransactionError encountered function runTransactionWithRetry(txnFunc, session) { while (true) { try { txnFunc(session); // performs transaction break; } catch (error) { // If transient error, retry the whole transaction if (error?.errorLabels?.includes("TransientTransactionError") ) { print("TransientTransactionError, retrying transaction ..."); continue; } else { throw error; } } } } // Retries commit if UnknownTransactionCommitResult encountered function commitWithRetry(session) { while (true) { try { session.commitTransaction(); // Uses write concern set at transaction start. print("Transaction committed."); break; } catch (error) { // Can retry commit if (error?.errorLabels?.includes("UnknownTransactionCommitResult") ) { print("UnknownTransactionCommitResult, retrying commit operation ..."); continue; } else { print("Error during commit ..."); throw error; } } } } // Updates two collections in a transactions function updateEmployeeInfo(session) { employeesCollection = session.getDatabase("hr").employees; eventsCollection = session.getDatabase("reporting").events; session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } ); try{ employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } ); eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } ); } catch (error) { print("Caught exception during transaction, aborting."); session.abortTransaction(); throw error; } commitWithRetry(session); } // Start a session. session = db.getMongo().startSession( { readPreference: { mode: "primary" } } ); try{ runTransactionWithRetry(updateEmployeeInfo, session); } catch (error) { // Do something with error } finally { session.endSession(); }