트랜잭션
MongoDB에서 단일 문서에 대한 작업은 원자적으로 이루어집니다. 임베디드 문서와 배열을 사용하면 여러 문서와 컬렉션에 걸쳐 정규화하는 대신 단일 문서 구조에서 데이터 간의 관계를 캡처할 수 있으므로 이러한 단일 문서 원자성은 많은 실제 사용 사례에서 분산 트랜잭션의 필요성을 없애줍니다.
여러 문서 (단일 또는 여러 컬렉션)에 대한 읽기 및 쓰기의 원자성이 필요한 상황의 경우, MongoDB는 분산 트랜잭션을 지원합니다. 분산 트랜잭션을 사용하면 여러 작업, 컬렉션, 데이터베이스, 문서 및 샤드에서 트랜잭션을 사용할 수 있습니다.
이 페이지의 정보는 다음 환경에서 호스팅되는 배포에 적용됩니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
트랜잭션 API
➤ 오른쪽 위에 있는 언어 선택 드롭다운 메뉴를 사용하여 다음 예시의 언어를 설정하세요.
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
static bool with_transaction_example (bson_error_t *error) { mongoc_client_t *client = NULL; mongoc_write_concern_t *wc = NULL; mongoc_collection_t *coll = NULL; bool success = false; bool ret = false; bson_t *doc = NULL; bson_t *insert_opts = NULL; mongoc_client_session_t *session = NULL; mongoc_transaction_opt_t *txn_opts = NULL; /* For a replica set, include the replica set name and a seedlist of the * members in the URI string; e.g. * uri_repl = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:" \ * "27017/?replicaSet=myRepl"; * client = mongoc_client_new (uri_repl); * For a sharded cluster, connect to the mongos instances; e.g. * uri_sharded = * "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; * client = mongoc_client_new (uri_sharded); */ client = get_client (); /* Prereq: Create collections. Note Atlas connection strings include a majority write * concern by default. */ wc = mongoc_write_concern_new (); mongoc_write_concern_set_wmajority (wc, 0); insert_opts = bson_new (); mongoc_write_concern_append (wc, insert_opts); coll = mongoc_client_get_collection (client, "mydb1", "foo"); doc = BCON_NEW ("abc", BCON_INT32 (0)); ret = mongoc_collection_insert_one (coll, doc, insert_opts, NULL /* reply */, error); if (!ret) { goto fail; } bson_destroy (doc); mongoc_collection_destroy (coll); coll = mongoc_client_get_collection (client, "mydb2", "bar"); doc = BCON_NEW ("xyz", BCON_INT32 (0)); ret = mongoc_collection_insert_one (coll, doc, insert_opts, NULL /* reply */, error); if (!ret) { goto fail; } /* Step 1: Start a client session. */ session = mongoc_client_start_session (client, NULL /* opts */, error); if (!session) { goto fail; } /* Step 2: Optional. Define options to use for the transaction. */ txn_opts = mongoc_transaction_opts_new (); mongoc_transaction_opts_set_write_concern (txn_opts, wc); /* Step 3: Use mongoc_client_session_with_transaction to start a transaction, * execute the callback, and commit (or abort on error). */ ret = mongoc_client_session_with_transaction (session, callback, txn_opts, NULL /* ctx */, NULL /* reply */, error); if (!ret) { goto fail; } success = true; fail: bson_destroy (doc); mongoc_collection_destroy (coll); bson_destroy (insert_opts); mongoc_write_concern_destroy (wc); mongoc_transaction_opts_destroy (txn_opts); mongoc_client_session_destroy (session); mongoc_client_destroy (client); return success; } /* Define the callback that specifies the sequence of operations to perform * inside the transactions. */ static bool callback (mongoc_client_session_t *session, void *ctx, bson_t **reply, bson_error_t *error) { mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; bson_t *doc = NULL; bool success = false; bool ret = false; BSON_UNUSED (ctx); client = mongoc_client_session_get_client (session); coll = mongoc_client_get_collection (client, "mydb1", "foo"); doc = BCON_NEW ("abc", BCON_INT32 (1)); ret = mongoc_collection_insert_one (coll, doc, NULL /* opts */, *reply, error); if (!ret) { goto fail; } bson_destroy (doc); mongoc_collection_destroy (coll); coll = mongoc_client_get_collection (client, "mydb2", "bar"); doc = BCON_NEW ("xyz", BCON_INT32 (999)); ret = mongoc_collection_insert_one (coll, doc, NULL /* opts */, *reply, error); if (!ret) { goto fail; } success = true; fail: mongoc_collection_destroy (coll); bson_destroy (doc); return success; }
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
// The mongocxx::instance constructor and destructor initialize and shut down the driver, // respectively. Therefore, a mongocxx::instance must be created before using the driver and // must remain alive for as long as the driver is in use. mongocxx::instance inst{}; // For a replica set, include the replica set name and a seedlist of the members in the URI // string; e.g. // uriString = // 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' // For a sharded cluster, connect to the mongos instances; e.g. // uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' mongocxx::client client{mongocxx::uri{"mongodb://localhost/?replicaSet=repl0"}}; // Prepare to set majority write explicitly. Note: on Atlas deployments this won't always be // needed. The suggested Atlas connection string includes majority write concern by default. write_concern wc_majority{}; wc_majority.acknowledge_level(write_concern::level::k_majority); // Prereq: Create collections. auto foo = client["mydb1"]["foo"]; auto bar = client["mydb2"]["bar"]; try { options::insert opts; opts.write_concern(wc_majority); foo.insert_one(make_document(kvp("abc", 0)), opts); bar.insert_one(make_document(kvp("xyz", 0)), opts); } catch (const mongocxx::exception& e) { std::cout << "An exception occurred while inserting: " << e.what() << std::endl; return EXIT_FAILURE; } // Step 1: Define the callback that specifies the sequence of operations to perform inside the // transactions. client_session::with_transaction_cb callback = [&](client_session* session) { // Important:: You must pass the session to the operations. foo.insert_one(*session, make_document(kvp("abc", 1))); bar.insert_one(*session, make_document(kvp("xyz", 999))); }; // Step 2: Start a client session auto session = client.start_session(); // Step 3: Use with_transaction to start a transaction, execute the callback, // and commit (or abort on error). try { options::transaction opts; opts.write_concern(wc_majority); session.with_transaction(callback, opts); } catch (const mongocxx::exception& e) { std::cout << "An exception occurred: " << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS;
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // string uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl"; // For a sharded cluster, connect to the mongos instances; e.g. // string uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; var client = new MongoClient(connectionString); // Prereq: Create collections. var database1 = client.GetDatabase("mydb1"); var collection1 = database1.GetCollection<BsonDocument>("foo").WithWriteConcern(WriteConcern.WMajority); collection1.InsertOne(new BsonDocument("abc", 0)); var database2 = client.GetDatabase("mydb2"); var collection2 = database2.GetCollection<BsonDocument>("bar").WithWriteConcern(WriteConcern.WMajority); collection2.InsertOne(new BsonDocument("xyz", 0)); // Step 1: Start a client session. using (var session = client.StartSession()) { // Step 2: Optional. Define options to use for the transaction. var transactionOptions = new TransactionOptions( writeConcern: WriteConcern.WMajority); // Step 3: Define the sequence of operations to perform inside the transactions var cancellationToken = CancellationToken.None; // normally a real token would be used result = session.WithTransaction( (s, ct) => { try { collection1.InsertOne(s, new BsonDocument("abc", 1), cancellationToken: ct); collection2.InsertOne(s, new BsonDocument("xyz", 999), cancellationToken: ct); } catch (MongoWriteException) { // Do something in response to the exception throw; // NOTE: You must rethrow the exception otherwise an infinite loop can occur. } return "Inserted into collections in different databases"; }, transactionOptions, cancellationToken); }
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
// WithTransactionExample is an example of using the Session.WithTransaction function. func WithTransactionExample(ctx context.Context) error { // For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // uri := "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl" // For a sharded cluster, connect to the mongos instances; e.g. // uri := "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/" uri := mtest.ClusterURI() clientOpts := options.Client().ApplyURI(uri) client, err := mongo.Connect(clientOpts) if err != nil { return err } defer func() { _ = client.Disconnect(ctx) }() // Prereq: Create collections. wcMajority := writeconcern.Majority() wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority) fooColl := client.Database("mydb1").Collection("foo", wcMajorityCollectionOpts) barColl := client.Database("mydb1").Collection("bar", wcMajorityCollectionOpts) // Step 1: Define the callback that specifies the sequence of operations to perform inside the transaction. callback := func(sesctx context.Context) (interface{}, error) { // Important: You must pass sesctx as the Context parameter to the operations for them to be executed in the // transaction. if _, err := fooColl.InsertOne(sesctx, bson.D{{"abc", 1}}); err != nil { return nil, err } if _, err := barColl.InsertOne(sesctx, bson.D{{"xyz", 999}}); err != nil { return nil, err } return nil, nil } // Step 2: Start a session and run the callback using WithTransaction. session, err := client.StartSession() if err != nil { return err } defer session.EndSession(ctx) result, err := session.WithTransaction(ctx, callback) if err != nil { return err } log.Printf("result: %v\n", result) return nil }
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
/* For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl"; For a sharded cluster, connect to the mongos instances. For example: String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin"; */ final MongoClient client = MongoClients.create(uri); /* Create collections. */ client.getDatabase("mydb1").getCollection("foo") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0)); client.getDatabase("mydb2").getCollection("bar") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0)); /* Step 1: Start a client session. */ final ClientSession clientSession = client.startSession(); /* Step 2: Optional. Define options to use for the transaction. */ TransactionOptions txnOptions = TransactionOptions.builder() .writeConcern(WriteConcern.MAJORITY) .build(); /* Step 3: Define the sequence of operations to perform inside the transactions. */ TransactionBody txnBody = new TransactionBody<String>() { public String execute() { MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo"); MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar"); /* Important:: You must pass the session to the operations. */ coll1.insertOne(clientSession, new Document("abc", 1)); coll2.insertOne(clientSession, new Document("xyz", 999)); return "Inserted into collections in different databases"; } }; try { /* Step 4: Use .withTransaction() to start a transaction, execute the callback, and commit (or abort on error). */ clientSession.withTransaction(txnBody, txnOptions); } catch (RuntimeException e) { // some error handling } finally { clientSession.close(); }
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = AsyncIOMotorClient(uriString) wc_majority = WriteConcern("majority", wtimeout=1000) # Prereq: Create collections. await client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0}) await client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0}) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. async def callback(my_session): collection_one = my_session.client.mydb1.foo collection_two = my_session.client.mydb2.bar # Important:: You must pass the session to the operations. await collection_one.insert_one({"abc": 1}, session=my_session) await collection_two.insert_one({"xyz": 999}, session=my_session) # Step 2: Start a client session. async with await client.start_session() as session: # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). await session.with_transaction( callback, read_concern=ReadConcern("local"), write_concern=wc_majority, read_preference=ReadPreference.PRIMARY, )
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // const uri = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' // For a sharded cluster, connect to the mongos instances; e.g. // const uri = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' const client = new MongoClient(uri); await client.connect(); // Prereq: Create collections. await client .db('mydb1') .collection('foo') .insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } }); await client .db('mydb2') .collection('bar') .insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } }); // Step 1: Start a Client Session const session = client.startSession(); // Step 2: Optional. Define options to use for the transaction const transactionOptions = { readPreference: 'primary', readConcern: { level: 'local' }, writeConcern: { w: 'majority' } }; // Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error) // Note: The callback for withTransaction MUST be async and/or return a Promise. try { await session.withTransaction(async () => { const coll1 = client.db('mydb1').collection('foo'); const coll2 = client.db('mydb2').collection('bar'); // Important:: You must pass the session to the operations await coll1.insertOne({ abc: 1 }, { session }); await coll2.insertOne({ xyz: 999 }, { session }); }, transactionOptions); } finally { await session.endSession(); await client.close(); }
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
sub runTransactionWithRetry { my ( $txnFunc, $session ) = @_; LOOP: { eval { $txnFunc->($session); # performs transaction }; if ( my $error = $@ ) { print("Transaction aborted-> Caught exception during transaction.\n"); # If transient error, retry the whole transaction if ( $error->has_error_label("TransientTransactionError") ) { print("TransientTransactionError, retrying transaction ->..\n"); redo LOOP; } else { die $error; } } } return; } sub commitWithRetry { my ($session) = @_; LOOP: { eval { $session->commit_transaction(); # Uses write concern set at transaction start. print("Transaction committed->\n"); }; if ( my $error = $@ ) { # Can retry commit if ( $error->has_error_label("UnknownTransactionCommitResult") ) { print("UnknownTransactionCommitResult, retrying commit operation ->..\n"); redo LOOP; } else { print("Error during commit ->..\n"); die $error; } } } return; } # Updates two collections in a transactions sub updateEmployeeInfo { my ($session) = @_; my $employeesCollection = $session->client->ns("hr.employees"); my $eventsCollection = $session->client->ns("reporting.events"); $session->start_transaction( { readConcern => { level => "snapshot" }, writeConcern => { w => "majority" }, readPreference => 'primary', } ); eval { $employeesCollection->update_one( { employee => 3 }, { '$set' => { status => "Inactive" } }, { session => $session}, ); $eventsCollection->insert_one( { employee => 3, status => { new => "Inactive", old => "Active" } }, { session => $session}, ); }; if ( my $error = $@ ) { print("Caught exception during transaction, aborting->\n"); $session->abort_transaction(); die $error; } commitWithRetry($session); } # Start a session my $session = $client->start_session(); eval { runTransactionWithRetry(\&updateEmployeeInfo, $session); }; if ( my $error = $@ ) { # Do something with error } $session->end_session();
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
/* * For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. * uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' * For a sharded cluster, connect to the mongos instances; e.g. * uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' */ $client = new \MongoDB\Client($uriString); // Prerequisite: Create collections. $client->selectCollection( 'mydb1', 'foo', [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000), ], )->insertOne(['abc' => 0]); $client->selectCollection( 'mydb2', 'bar', [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000), ], )->insertOne(['xyz' => 0]); // Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. $callback = function (\MongoDB\Driver\Session $session) use ($client): void { $client ->selectCollection('mydb1', 'foo') ->insertOne(['abc' => 1], ['session' => $session]); $client ->selectCollection('mydb2', 'bar') ->insertOne(['xyz' => 999], ['session' => $session]); }; // Step 2: Start a client session. $session = $client->startSession(); // Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). \MongoDB\with_transaction($session, $callback);
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = MongoClient(uriString) wc_majority = WriteConcern("majority", wtimeout=1000) # Prereq: Create collections. client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0}) client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0}) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. def callback(session): collection_one = session.client.mydb1.foo collection_two = session.client.mydb2.bar # Important:: You must pass the session to the operations. collection_one.insert_one({"abc": 1}, session=session) collection_two.insert_one({"xyz": 999}, session=session) # Step 2: Start a client session. with client.start_session() as session: # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). session.with_transaction( callback, read_concern=ReadConcern("local"), write_concern=wc_majority, read_preference=ReadPreference.PRIMARY, )
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uri_string = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = Mongo::Client.new(uri_string, write_concern: {w: :majority, wtimeout: 1000}) # Prereq: Create collections. client.use('mydb1')['foo'].insert_one(abc: 0) client.use('mydb2')['bar'].insert_one(xyz: 0) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. callback = Proc.new do |my_session| collection_one = client.use('mydb1')['foo'] collection_two = client.use('mydb2')['bar'] # Important: You must pass the session to the operations. collection_one.insert_one({'abc': 1}, session: my_session) collection_two.insert_one({'xyz': 999}, session: my_session) end #. Step 2: Start a client session. session = client.start_session # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). session.with_transaction( read_concern: {level: :local}, write_concern: {w: :majority, wtimeout: 1000}, read: {mode: :primary}, &callback)
이 예에서는 트랜잭션 API의 주요 구성요소를 강조합니다. 특히 콜백 API를 사용합니다. 콜백 API:
트랜잭션을 시작합니다.
지정된 작업을 실행합니다.
결과를 커밋하거나 오류가 발생하여 트랜잭션 을 종료합니다.
DuplicateKeyError
같은 서버 측 작업의 오류로 인해 트랜잭션이 종료되고 사용자에게 트랜잭션이 종료되었음을 알리는 명령 오류가 발생할 수 있습니다. 이 동작은 예상된 것이며 클라이언트가 Session.abortTransaction()
를 호출하지 않는 경우에도 발생합니다. 사용자 지정 오류 처리를 통합하려면 트랜잭션에서 Core API 를 사용하세요.
콜백 Callback API API 는 특정 오류에 대한 재시도 로직을 통합합니다. 운전자 는 TransientTransactionError 또는 UnknownTransactionCommitResult 커밋 오류 후에 트랜잭션 을 다시 실행하려고 시도합니다.
MongoDB 6.0.5 부터 서버는 TransactionTooLargeForCache 오류를 수신하면 트랜잭션을 재시도하지 않습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
// For a replica set, include the replica set name and a seedlist of the members in the URI // string; e.g. let uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/? // replicaSet=myRepl"; For a sharded cluster, connect to the mongos instances; e.g. // let uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; let client = Client::with_uri_str(uri).await?; // Prereq: Create collections. CRUD operations in transactions must be on existing collections. client .database("mydb1") .collection::<Document>("foo") .insert_one(doc! { "abc": 0}) .await?; client .database("mydb2") .collection::<Document>("bar") .insert_one(doc! { "xyz": 0}) .await?; // Step 1: Define the callback that specifies the sequence of operations to perform inside the // transaction. async fn callback(session: &mut ClientSession) -> Result<()> { let collection_one = session .client() .database("mydb1") .collection::<Document>("foo"); let collection_two = session .client() .database("mydb2") .collection::<Document>("bar"); // Important: You must pass the session to the operations. collection_one .insert_one(doc! { "abc": 1 }) .session(&mut *session) .await?; collection_two .insert_one(doc! { "xyz": 999 }) .session(session) .await?; Ok(()) } // Step 2: Start a client session. let mut session = client.start_session().await?; // Step 3: Use and_run to start a transaction, execute the callback, and commit (or // abort on error). session .start_transaction() .and_run((), |session, _| callback(session).boxed()) .await?;
이 예제에서는 core API를 사용합니다. 핵심 API 에는 TransientTransactionError
또는 UnknownTransactionCommitResult
커밋 오류에 대한 재시도 로직이 통합되어 있지 않으므로 이 예시 에는 이러한 오류에 대해 트랜잭션 을 재시도하는 명시적인 로직이 포함되어 있습니다.
중요
MongoDB 버전에 맞는 MongoDB 드라이버를 사용하세요.
드라이버를 사용할 때 트랜잭션의 각 작업은 각 작업에 세션을 전달해야 합니다.
트랜잭션의 작업은 트랜잭션 수준의 읽기 고려, 트랜잭션 수준의 쓰기 고려, 트랜잭션 수준의 읽기 설정을 사용합니다.
트랜잭션에서 암시적 또는 명시적으로 컬렉션을 만들 수 있습니다. 트랜잭션에서 컬렉션 및 인덱스 생성을 참조하세요.
/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mongodb.scala import org.mongodb.scala.model.{Filters, Updates} import org.mongodb.scala.result.UpdateResult import scala.concurrent.Await import scala.concurrent.duration.Duration //scalastyle:off magic.number class DocumentationTransactionsExampleSpec extends RequiresMongoDBISpec { // Implicit functions that execute the Observable and return the results val waitDuration = Duration(5, "seconds") implicit class ObservableExecutor[T](observable: Observable[T]) { def execute(): Seq[T] = Await.result(observable.toFuture(), waitDuration) } implicit class SingleObservableExecutor[T](observable: SingleObservable[T]) { def execute(): T = Await.result(observable.toFuture(), waitDuration) } // end implicit functions "The Scala driver" should "be able to commit a transaction" in withClient { client => assume(serverVersionAtLeast(List(4, 0, 0)) && !hasSingleHost()) client.getDatabase("hr").drop().execute() client.getDatabase("hr").createCollection("employees").execute() client.getDatabase("hr").createCollection("events").execute() updateEmployeeInfoWithRetry(client).execute() should equal(Completed()) client.getDatabase("hr").drop().execute() should equal(Completed()) } def updateEmployeeInfo(database: MongoDatabase, observable: SingleObservable[ClientSession]): SingleObservable[ClientSession] = { observable.map(clientSession => { val employeesCollection = database.getCollection("employees") val eventsCollection = database.getCollection("events") val transactionOptions = TransactionOptions.builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.SNAPSHOT) .writeConcern(WriteConcern.MAJORITY) .build() clientSession.startTransaction(transactionOptions) employeesCollection.updateOne(clientSession, Filters.eq("employee", 3), Updates.set("status", "Inactive")) .subscribe((res: UpdateResult) => println(res)) eventsCollection.insertOne(clientSession, Document("employee" -> 3, "status" -> Document("new" -> "Inactive", "old" -> "Active"))) .subscribe((res: Completed) => println(res)) clientSession }) } def commitAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = { observable.recoverWith({ case e: MongoException if e.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL) => { println("UnknownTransactionCommitResult, retrying commit operation ...") commitAndRetry(observable) } case e: Exception => { println(s"Exception during commit ...: $e") throw e } }) } def runTransactionAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = { observable.recoverWith({ case e: MongoException if e.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL) => { println("TransientTransactionError, aborting transaction and retrying ...") runTransactionAndRetry(observable) } }) } def updateEmployeeInfoWithRetry(client: MongoClient): SingleObservable[Completed] = { val database = client.getDatabase("hr") val updateEmployeeInfoObservable: Observable[ClientSession] = updateEmployeeInfo(database, client.startSession()) val commitTransactionObservable: SingleObservable[Completed] = updateEmployeeInfoObservable.flatMap(clientSession => clientSession.commitTransaction()) val commitAndRetryObservable: SingleObservable[Completed] = commitAndRetry(commitTransactionObservable) runTransactionAndRetry(commitAndRetryObservable) } }
트랜잭션 및 원자성
여러 문서(단일 또는 여러 컬렉션)에 대한 읽기 및 쓰기의 원자성이 필요한 상황의 경우, 복제본 세트 및 샤딩된 클러스터에서의 트랜잭션을 포함한 분산 트랜잭션을 지원합니다.
분산 트랜잭션은 다음과 같이 원자적입니다.
트랜잭션은 모든 데이터 변경 사항을 적용하거나 변경 사항을 롤백합니다.
트랜잭션이 커밋되면 트랜잭션에서 이루어진 모든 데이터 변경 사항이 저장되고 트랜잭션 외부에서 볼 수 있습니다.
트랜잭션이 커밋될 때까지 트랜잭션에서 변경된 데이터는 트랜잭션 외부에 표시되지 않습니다.
그러나 트랜잭션이 여러 샤드에 쓰기를 수행하는 경우, 모든 외부 읽기 작업이 커밋된 트랜잭션의 결과가 샤드 전체에 표시될 때까지 기다릴 필요는 없습니다. 예를 들어, 트랜잭션이 커밋되고 쓰기 1이 샤드 A에 표시되지만 쓰기 2가 샤드 B에 아직 표시되지 않는 경우, 읽기 고려
"local"
의 외부 읽기는 쓰기 2를 보지 않고 쓰기 1의 결과를 읽을 수 있습니다.트랜잭션이 중단되면 트랜잭션에서 발생한 모든 데이터 변경 사항은 표시되지 않고 삭제됩니다. 예를 들어, 트랜잭션의 작업이 실패하면 트랜잭션이 중단되고 트랜잭션의 모든 데이터 변경 사항이 표시되지 않은 채로 폐기됩니다.
중요
대부분의 경우 분산 트랜잭션은 단일 문서 쓰기에 비해 더 큰 성능 비용이 발생하므로 분산 트랜잭션의 가용성이 효과적인 스키마 설계를 대체할 수는 없습니다. 대부분의 시나리오에서 비정규화된 데이터 모델 (내장된 문서 및 배열) 은 계속해서 데이터 및 사용 사례에 최적일 것입니다. 즉, 대부분의 시나리오에서 데이터를 적절하게 모델링하면 분산 트랜잭션의 필요성이 최소화됩니다.
추가 트랜잭션 사용 고려 사항(예: 런타임 제한 및 oplog 크기 제한)은 프로덕션 고려사항을 참조하세요.
트랜잭션 및 작업
분산 트랜잭션은 여러 작업, 컬렉션, 데이터베이스, 문서 및 샤드 전반에 걸쳐 사용될 수 있습니다.
거래의 경우:
트랜잭션 내에서 컬렉션과 인덱스를 생성할 수 있습니다. 자세한 내용은 트랜잭션에서 컬렉션 및 인덱스 생성하기를 참조하세요.
트랜잭션에 사용되는 컬렉션은 서로 다른 데이터베이스에 있을 수 있습니다.
참고
샤드 간 쓰기 트랜잭션에서는 새 컬렉션을 생성할 수 없습니다. 예를 들어, 하나의 샤드에서 기존 컬렉션에 쓰고 다른 샤드에서 암시적으로 새 컬렉션을 생성하는 경우, MongoDB는 동일한 트랜잭션에서 두 작업을 모두 수행할 수 없습니다.
제한된 컬렉션에는 쓸 (write) 수 없습니다.
고정 사이즈 컬렉션에서 읽을 때는 읽기 고려
"snapshot"
을 사용할 수 없습니다. (MongoDB 5.0부터 도입됨)config
,admin
또는local
데이터베이스의 컬렉션을 읽고 쓸 수 없습니다.system.*
컬렉션에 쓸 수 없습니다.explain
또는 이와 유사한 명령을 사용하여 지원되는 작업의 쿼리 계획을 반환할 수 없습니다.
트랜잭션 외부에서 생성된 커서의 경우 트랜잭션 내부에서
getMore
을(를) 호출할 수 없습니다.트랜잭션에서 생성된 커서의 경우 트랜잭션 외부에서
getMore
를 호출할 수 없습니다.
killCursors
명령을 transaction의 첫 번째 작업으로 지정할 수 없습니다.또한 트랜잭션 내에서
killCursors
명령을 실행 하면 서버 가 지정된 커서를 즉시 중지합니다. 트랜잭션 이 커밋 될 때까지 기다리지 않습니다.
트랜잭션에서 지원되지 않는 작업 목록은 제한된 작업을 참조하세요.
팁
트랜잭션을 시작하기 직전에 컬렉션을 만들거나 제거할 때 트랜잭션 내에서 컬렉션에 액세스하는 경우 쓰기 고려 "majority"
가 있는 만들기 또는 제거 작업을 실행하여 트랜잭션이 필요한 잠금을 획득할 수 있도록 하세요.
트랜잭션에서 컬렉션 및 인덱스 생성
트랜잭션이 교차 샤드 쓰기 트랜잭션(write transaction)이 아닌 경우 분산 트랜잭션에서 다음 작업을 수행할 수 있습니다.
컬렉션을 생성합니다.
동일한 트랜잭션에서 이전에 생성된 새로운 빈 컬렉션에 인덱스를 생성.
트랜잭션 내에서 컬렉션을 만들 때
다음과 같이 컬렉션을 암시적으로 만들 수 있습니다.
존재하지 않는 컬렉션에 대한 삽입 작업 또는
존재하지 않는 컬렉션에 대해
upsert: true
을(를) 사용하여 업데이트/findAndModify 작업을 수행합니다.
db.createCollection()
명령 또는create
해당 도우미 을 사용하여 컬렉션을 명시적으로 만들 수 있습니다.
트랜잭션 내부에 인덱스를 생성 할 때 [1], 생성할 인덱스는 둘 중 하나에 있어야 합니다.
존재하지 않는 컬렉션입니다. 컬렉션은 작업의 일부로 생성됩니다.
동일한 트랜잭션에서 이전에 생성된 새 빈 컬렉션입니다.
[1] | 기존 인덱스에서 db.collection.createIndex() 및 db.collection.createIndexes() 를 실행하여 존재 여부를 확인할 수도 있습니다. 이러한 작업은 인덱스를 생성하지 않고 성공적으로 반환됩니다. |
제한 사항
샤드 간 쓰기 트랜잭션에서는 새 컬렉션을 생성할 수 없습니다. 예를 들어, 하나의 샤드에서 기존 컬렉션에 쓰고 다른 샤드에서 암시적으로 새 컬렉션을 생성하는 경우, MongoDB는 동일한 트랜잭션에서 두 작업을 모두 수행할 수 없습니다.
샤딩된 컬렉션을 대상으로 하는 동안 트랜잭션 내에서
$graphLookup
단계를 사용할 수 없습니다.트랜잭션 내에서 컬렉션이나 인덱스를 명시적으로 만들려면 트랜잭션 읽기 고려 수준이
"local"
여야 합니다.컬렉션 및 인덱스를 명시적으로 생성하려면 다음 명령과 메서드를 사용합니다.
카운트 연산
트랜잭션 내에서 카운트 연산을 수행하려면 $count
집계 단계 또는 $group
($sum
표현식 포함) 집계 단계를 사용합니다.
MongoDB 드라이버는 $sum
표현식과 함께 $group
를 사용하여 카운트를 수행하는 헬퍼 메서드로서 컬렉션 수준 API countDocuments(filter, options)
을 제공합니다.
mongosh
는 $sum
표현식과 함께 $group
을 사용하여 카운트를 수행하는 헬퍼 메서드 db.collection.countDocuments()
를 제공합니다.
차별화된 운영
트랜잭션 내에서 고유한 작업을 수행합니다.
샤드되지 않은 컬렉션의 경우,
db.collection.distinct()
메서드/distinct
명령과$group
단계의 집계 파이프라인을 사용할 수 있습니다.리샤드된 컬렉션의 경우
db.collection.distinct()
메서드 또는distinct
명령을 사용할 수 없습니다.샤딩된 컬렉션의 고유 값을 찾으려면 대신
$group
단계의 집계 파이프라인을 사용합니다. 예시:db.coll.distinct("x")
0} 대신 다음을 사용합니다.db.coll.aggregate([ { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ]) db.coll.distinct("x", { status: "A" })
0} 대신 다음을 사용합니다.db.coll.aggregate([ { $match: { status: "A" } }, { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ])
파이프라인은 문서에 커서를 반환합니다.
{ "distinctValues" : [ 2, 3, 1 ] } 커서를 반복하여 결과 문서에 액세스합니다.
정보 운영
2} buildInfo
,hello
connectionStatus
, 과 같은 정보 명령(및 그 도우미 메서드) (및 해당 헬퍼 메서드)와 같은 정보 명령은 트랜잭션에서 허용되지만, 트랜잭션의 첫 번째 연산이 될 수는 없습니다.
제한된 작업
트랜잭션에서 허용되지 않는 작업은 다음과 같습니다.
다중 샤드 쓰기 트랜잭션에서 새로운 컬렉션을 생성하기. 예를 들어 하나의 샤드에서 기존 컬렉션에 쓰고 다른 샤드에 암시적으로 컬렉션을 생성하는 경우 MongoDB는 동일한 트랜잭션에서 두 작업을 모두 수행할 수 없습니다.
컬렉션(예:
db.createCollection()
메서드) 및 인덱스(예:db.collection.createIndexes()
및db.collection.createIndex()
메서드)의 생성을"local"
이외의 읽기 고려 수준을 사용하는 경우 명시합니다.listCollections
2} 및 명령과 해당 도우미 메서드.listIndexes
createUser
,getParameter
,count
등과 해당 헬퍼와 같은 기타 비 CRUD 및 비 정보 작업입니다.
트랜잭션 및 세션
트랜잭션은 세션과 관련이 있습니다.
세션당 한 번에 최대 한 개의 열린 트랜잭션만 진행할 수 있습니다.
드라이버를 사용할 때 트랜잭션의 각 작업은 세션과 연결되어야 합니다. 자세한 내용은 드라이버별 문서를 참조하세요.
세션이 종료되고 열려 있는 트랜잭션이 있는 경우 트랜잭션이 중단됩니다.
읽기 고려/쓰기 고려/읽기 설정
트랜잭션 및 읽기 환경설정
트랜잭션의 작업에는 트랜잭션 수준 읽기 기본 설정이 사용됩니다.
드라이버를 사용하면 트랜잭션 시작 시 트랜잭션 수준 읽기 기본 설정을 지정할 수 있습니다.
트랜잭션 수준 읽기 설정이 지정되지 않은 경우 트랜잭션은 세션 수준 읽기 설정을 사용합니다.
트랜잭션 수준 및 세션 수준 읽기 설정이 설정되지 않은 경우 트랜잭션은 클라이언트 수준 읽기 설정을 사용합니다. 기본적으로 클라이언트 수준 읽기 설정은
primary
입니다.
읽기 작업이 포함된 분산 트랜잭션은 읽기 설정 primary
(을)를 사용해야 합니다. 특정 트랜잭션의 모든 작업은 동일한 구성원으로 라우팅되어야 합니다.
트랜잭션 및 읽기 우려
트랜잭션의 작업은 트랜잭션 수준 읽기 고려 (read concern)를 사용합니다. 즉, 컬렉션 및 데이터베이스 수준에서 설정된 읽기 고려 (read concern)는 트랜잭션 내부에서 무시됩니다.
트랜잭션 시작 시 트랜잭션 수준의 읽기 문제를 설정할 수 있습니다.
트랜잭션 수준 읽기 고려 (read concern)가 설정되지 않은 경우 트랜잭션 수준 읽기 고려는 기본적으로 세션 수준 읽기 고려로 설정됩니다.
트랜잭션 수준 및 세션 수준 읽기 고려 (read concern)가 설정되지 않은 경우, 트랜잭션 수준 읽기 고려 (read concern)는 기본적으로 클라이언트 수준 읽기 고려 (read concern)로 설정됩니다. 기본적으로 클라이언트 수준 읽기 고려 (read concern)는 프라이머리 읽기에서
"local"
입니다. 다음도 참조하세요.
트랜잭션은 다음과 같은 읽기 고려 수준을 지원합니다.
"local"
읽기 고려
"local"
는 노드에서 사용 가능한 가장 최근 데이터를 반환하지만 롤백할 수 있습니다.복제본 세트 에서는 트랜잭션 이 읽기 고려 (read concern)
local
을(를) 사용하더라도 트랜잭션 이 열린 점 에 스냅샷 에서 읽는 작업에서 더 강력한 읽기 격리 가 관찰될 수 있습니다.트랜잭션이 샤딩된 클러스터에 있는 경우,
"local"
읽기 고려는 데이터가 샤드 전체의 동리한 스냅샷 보기에서 나온 것임을 보장할 수 없습니다. 스냅샷 격리가 필요한 경우"snapshot"
읽기 고려를 사용하세요.트랜잭션 내에서 컬렉션과 인덱스를 생성할 수 있습니다. 컬렉션이나 인덱스를 명시적으로 생성하는 경우, 트랜잭션은 반드시 읽기 고려
"local"
(을)를 사용해야 합니다. 컬렉션을 암시적으로 생성하는 경우 사용 가능한 모든 읽기 고려를 트랜잭션에 사용할 수 있습니다.
"majority"
트랜잭션이 쓰기 고려 "majority"로 커밋되면 읽기 고려
"majority"
는 복제본 세트 멤버의 과반수가 인정한 데이터를 반환하며, 이는 롤백할 수 없습니다. 그렇지 않으면 읽기 고려"majority"
는 읽기 작업이 과반수가 커밋된 데이터를 읽는다는 보장을 제공하지 않습니다.샤딩된 클러스터에서의 트랜잭션의 경우, 읽기 고려
"majority"
는 샤드 전체에서 동일한 스냅샷 뷰의 데이터임을 보장할 수 없습니다. 스냅샷 격리가 필요한 경우 읽기 고려"snapshot"
을 사용하세요.
"snapshot"
읽기 고려
"snapshot"
는 트랜잭션이 쓰기 고려 "majority"로 커밋된 경우 대다수 커밋된 데이터의 스냅샷에서 데이터를 반환합니다.트랜잭션이 커밋에 대해 쓰기 고려 "majority"를 사용하지 않는 경우,
"snapshot"
읽기 고려는 읽기 작업이 과반수 커밋된 데이터의 스냅샷을 사용했다는 보장을 제공하지 않습니다.샤딩된 클러스터의 트랜잭션의 경우, 데이터의
"snapshot"
보기가 샤드 간에 동기화됩니다.
트랜잭션 및 쓰기 고려
트랜잭션은 트랜잭션 수준 쓰기 고려 (write concern)를 사용하여 쓰기 (write) 작업을 커밋합니다. 트랜잭션 내부의 쓰기 (write) 작업은 명시적인 쓰기 고려 (write concern) 지정 없이 실행되어야 하며 기본값 쓰기 고려 (write concern)를 사용해야 합니다. 커밋 시 트랜잭션 수준 쓰기 고려 (write concern)를 사용하여 쓰기 (write)가 커밋됩니다.
팁
트랜잭션 내부의 개별 쓰기 (write) 작업에 대한 쓰기 고려 (write concern)를 명시적으로 설정하지 마세요. 트랜잭션 내부의 개별 쓰기 (write) 작업에 대한 쓰기 고려 (write concern)를 설정하면 오류가 반환됩니다.
트랜잭션 시작 시 트랜잭션 수준 쓰기 문제를 설정할 수 있습니다.
트랜잭션 수준 쓰기 고려 (write concern)가 설정되지 않은 경우, 트랜잭션 수준 쓰기 고려는 커밋에 대한 세션 수준 쓰기 고려를 기본값으로 사용합니다.
트랜잭션 수준 쓰기 고려 (write concern)와 세션 수준 쓰기 고려가 설정되지 않은 경우 트랜잭션 수준 쓰기 고려는 기클라이언트 수준 쓰기 고려를 기본값으로 사용합니다.
MongoDB 5.0의
w: "majority"
및 그 이상에서는 중재자가 포함된 배포의 경우 차이가 있습니다. 암시적 기본 쓰기 문제를 참조하세요.
트랜잭션은 다음을 포함한 모든 쓰기 고려 w 값을 지원합니다.
w: 1
쓰기 고려
w: 1
은 커밋이 프라이머리에 적용된 후 승인을 반환합니다.중요
w: 1
로 커밋할 때 페일오버가 있는 경우 트랜잭션을 롤백할 수 있습니다.w: 1
쓰기 고려로"majority"
커밋하는 경우 트랜잭션 수준 읽기 고려는 트랜잭션의 읽기 작업이 대다수 커밋된 데이터를 읽지 않는다는 보장을 제공하지 않습니다.w: 1
쓰기 고려로 커밋하는 경우 트랜잭션 수준"snapshot"
읽기 고려는 트랜잭션의 읽기 작업이 대다수 커밋된 데이터의 스냅샷을 사용했다는 보장을 제공하지 않습니다.
w: "majority"
쓰기 고려
w: "majority"
는 투표 노드 과반수에게 커밋이 적용된 후 승인을 반환합니다.w: "majority"
쓰기 고려로 커밋하는 경우 트랜잭션 수준"majority"
읽기 고려는 작업이 대다수 커밋된 데이터를 읽었음을 보장합니다. 샤딩된 클러스터의 트랜잭션의 경우 대부분 커밋된 데이터에 대한 이 보기는 샤드 전체에서 동기화되지 않습니다.w: "majority"
2} 쓰기 고려로 커밋할 때 트랜잭션 수준"snapshot"
읽기 고려는 작업이 대다수 커밋된 데이터의 동기화된 스냅샷에서 읽은 것을 보장합니다.
참고
트랜잭션에 지정된 쓰기 고려와 관계없이, 샤딩된 클러스터 트랜잭션에 대한 커밋 작업에는 {w:
"majority", j: true}
쓰기 고려를 사용하는 일부 부분이 포함됩니다.
서버 매개변수 coordinateCommitReturnImmediatelyAfterPersistingDecision
는 트랜잭션 커밋 결정이 클라이언트에 반환되는 시기를 제어합니다.
이 매개 변수는 MongDB 5.0에서 기본값이 true
로 도입되었습니다. MongoDB 6.0 및 5.0.10에서는 기본값이 false
으로 변경됩니다.
coordinateCommitReturnImmediatelyAfterPersistingDecision
이 false
가 되면 샤드 트랜잭션 코디네이터는 모든 멤버가 다중 문서 트랜잭션 커밋을 승인할 때까지 기다린 다음 커밋 결정을 클라이언트에 반환합니다.
다중 문서 트랜잭션 에 대해 "majority"
쓰기 고려를 지정했는데 트랜잭션이 계산된 과반수 복제본 세트 멤버에 복제하지 못하는 경우 트랜잭션이 복제본 세트 멤버를 즉시 롤백하지 않을 수 있습니다. 복제본 세트는 최종 일관성을 갖 습니다. 트랜잭션은 항상 모든 복제본 세트 멤버에 적용되거나 롤백됩니다.
트랜잭션에 지정된 쓰기 고려에 관계없이 드라이버는 commitTransaction
(을)를 재시도할 때 쓰기 고려로 w: "majority"
(을)를 적용합니다
일반 정보
다음 섹션에서는 트랜잭션에 대한 추가 고려 사항을 설명합니다.
프로덕션 고려 사항
프로덕션 환경에서의 트랜잭션에 대해서는 프로덕션 고려 사항을 참조하세요. 또한 샤딩된 클러스터의 경우 프로덕션 고려 사항(샤딩된 클러스터)을 참조하세요.
중재자
복제본 세트 에 중재자 가 있는 경우 트랜잭션 을 사용하여 샤드 키 를 변경할 수 없습니다. 중재자는 멀티 샤드 트랜잭션에 필요한 데이터 작업에 참여할 수 없습니다.
쓰기 작업이 여러 샤드에 걸쳐 있는 트랜잭션은 트랜잭션 작업 중 어떤 것이든 중재자가 포함된 샤드에서 읽거나 쓰는 경우 오류를 발생시키고 중단됩니다.
샤드 구성 제한
writeConcernMajorityJournalDefault
가 false
로 설정된 샤드가 있는 샤딩된 클러스터에서는 트랜잭션을 실행할 수 없습니다. (예: 인메모리 스토리지 엔진을 사용하는 투표 멤버가 있는 샤드)
참고
트랜잭션에 지정된 쓰기 고려와 관계없이, 샤딩된 클러스터 트랜잭션에 대한 커밋 작업에는 {w:
"majority", j: true}
쓰기 고려를 사용하는 일부 부분이 포함됩니다.
진단
트랜잭션 상태 및 지표를 얻으려면 다음 메서드를 사용하세요.
소스 | 반환 |
---|---|
db.serverStatus() methodserverStatus command | |
$currentOp 집계 파이프라인 | 반환합니다:
|
db.currentOp() methodcurrentOp command | 반환합니다:
|
TXN 로그 구성 요소에 느린 트랜잭션(operationProfiling.slowOpThresholdMs 임계값을 초과하는 트랜잭션)에 대한 정보를 포함합니다. |
기능 호환 버전(fCV)
트랜잭션을 사용하려면 디플로이먼트의 모든 멤버에 대한 FeatureCompatibilityVersion이 최소한 다음과 같아야 합니다.
배포 | 최소 featureCompatibilityVersion |
---|---|
복제본 세트 | 4.0 |
샤딩된 클러스터 | 4.2 |
멤버의 fCV를 확인하려면 해당 멤버에 연결하고 다음 명령을 실행하세요.
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
자세한 내용은 setFeatureCompatibilityVersion
도움말 페이지를 참조하세요.
스토리지 엔진
복제본 세트와 샤딩된 클러스터에서 지원되는 분산 트랜잭션은 다음 조건에서 사용할 수 있습니다.
프라이머리는 WiredTiger 스토리지 엔진을 사용합니다.
보조 멤버는 와이어드타이거 스토리지 엔진 또는 인메모리 스토리지 엔진을 사용합니다.
참고
storage engine 을 사용하는 투표 멤버가 있는 샤드와 같이 로 설정된 샤드가 있는 cluster에서는 트랜잭션을 실행할 수 없습니다.writeConcernMajorityJournalDefault
false
중요 구간 대기 시간 제한
MongoDB 5.2(및 5.0.4)부터 시작됩니다.
쿼리가 분할된 데이터베이스에 액세스할 때 청크 마이그레이션 또는 DDL 작업은 컬렉션에 대한 중요한 섹션을 보유할 수 있습니다.
샤드가 트랜잭션 내 중요 섹션까지 대기하는 시간을 제한하려면
metadataRefreshInTransactionMaxWaitBehindCritSecMS
매개변수를 사용하세요.