Docs Menu

ํŠธ๋žœ์žญ์…˜

MongoDB์—์„œ ๋‹จ์ผ ๋ฌธ์„œ์— ๋Œ€ํ•œ ์ž‘์—…์€ ์›์ž์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์ž„๋ฒ ๋””๋“œ ๋ฌธ์„œ์™€ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ฌธ์„œ์™€ ์ปฌ๋ ‰์…˜์— ๊ฑธ์ณ ์ •๊ทœํ™”ํ•˜๋Š” ๋Œ€์‹  ๋‹จ์ผ ๋ฌธ์„œ ๊ตฌ์กฐ์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ๋‹จ์ผ ๋ฌธ์„œ ์›์ž์„ฑ์€ ๋งŽ์€ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์˜ ํ•„์š”์„ฑ์„ ์—†์• ์ค๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๋ฌธ์„œ (๋‹จ์ผ ๋˜๋Š” ์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜)์— ๋Œ€ํ•œ ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ์˜ ์›์ž์„ฑ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์˜ ๊ฒฝ์šฐ, MongoDB๋Š” ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ์ž‘์—…, ์ปฌ๋ ‰์…˜, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ๋ฌธ์„œ ๋ฐ ์ƒค๋“œ์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€์˜ ์ •๋ณด๋Š” ๋‹ค์Œ ํ™˜๊ฒฝ์—์„œ ํ˜ธ์ŠคํŒ…๋˜๋Š” ๋ฐฐํฌ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • MongoDB Atlas: ํด๋ผ์šฐ๋“œ์—์„œ์˜ MongoDB ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ์™„์ „ ๊ด€๋ฆฌํ˜• ์„œ๋น„์Šค

  • MongoDB Enterprise: MongoDB์˜ ๊ตฌ๋… ๊ธฐ๋ฐ˜ ์ž์ฒด ๊ด€๋ฆฌ ๋ฒ„์ „

  • MongoDB Community: MongoDB์˜ ์†Œ์Šค ์‚ฌ์šฉ ๊ฐ€๋Šฅ ๋ฌด๋ฃŒ ์ž์ฒด ๊ด€๋ฆฌ ๋ฒ„์ „


โžค ์˜ค๋ฅธ์ชฝ ์œ„์— ์žˆ๋Š” ์–ธ์–ด ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์˜ˆ์‹œ์˜ ์–ธ์–ด๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.


์ด ์˜ˆ์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜ API์˜ ์ฃผ์š” ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์ฝœ๋ฐฑ API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ API:

  • ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ์ง€์ •๋œ ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฒฐ๊ณผ๋ฅผ ์ปค๋ฐ‹ํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

DuplicateKeyError์™€ ๊ฐ™์€ ์„œ๋ฒ„ ์ธก ์ž‘์—…์˜ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋˜์—ˆ์Œ์„ ์•Œ๋ฆฌ๋Š” ๋ช…๋ น ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋™์ž‘์€ ์˜ˆ์ƒ๋œ ๊ฒƒ์ด๋ฉฐ ํด๋ผ์ด์–ธํŠธ๊ฐ€ Session.abortTransaction()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋„ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ฉํ•˜๋ ค๋ฉด ํŠธ๋žœ์žญ์…˜์—์„œ Core API๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ฝœ๋ฐฑ Callback API API ๋Š” ํŠน์ • ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์žฌ์‹œ๋„ ๋กœ์ง์„ ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์šด์ „์ž ๋Š” TransientTransactionError ๋˜๋Š” UnknownTransactionCommitResult ์ปค๋ฐ‹ ์˜ค๋ฅ˜ ํ›„์— ํŠธ๋žœ์žญ์…˜ ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

MongoDB 6.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

// 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 (mongocxx::exception const& 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 (mongocxx::exception const& 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

// 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

// 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

/*
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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

# 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

// 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

/*
* 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

# 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

# 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.2๋ถ€ํ„ฐ ์„œ๋ฒ„๋Š” TransactionTooLargeForCache ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”

// 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 ์ปค๋ฐ‹ ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์žฌ์‹œ๋„ ๋กœ์ง์ด ํ†ตํ•ฉ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ์˜ˆ์‹œ ์—๋Š” ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ํŠธ๋žœ์žญ์…˜ ์„ ์žฌ์‹œ๋„ํ•˜๋Š” ๋ช…์‹œ์ ์ธ ๋กœ์ง์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”

/*
* 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)
}
}

ํŒ

๋‹ค์Œ๋„ ์ฐธ์กฐํ•˜์„ธ์š”.

mongosh์˜ ์˜ˆ์‹œ๋Š” mongosh ์˜ˆ์‹œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์—ฌ๋Ÿฌ ๋ฌธ์„œ(๋‹จ์ผ ๋˜๋Š” ์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜)์— ๋Œ€ํ•œ ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ์˜ ์›์ž์„ฑ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์˜ ๊ฒฝ์šฐ, ๋ณต์ œ๋ณธ ์„ธํŠธ ๋ฐ ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ์˜ ํŠธ๋žœ์žญ์…˜์„ ํฌํ•จํ•œ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์›์ž์ ์ž…๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์€ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋กค๋ฐฑํ•ฉ๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๋ฉด ํŠธ๋žœ์žญ์…˜์—์„œ ์ด๋ฃจ์–ด์ง„ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ €์žฅ๋˜๊ณ  ํŠธ๋žœ์žญ์…˜ ์™ธ๋ถ€์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋  ๋•Œ๊นŒ์ง€ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋Š” ํŠธ๋žœ์žญ์…˜ ์™ธ๋ถ€์— ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜ ํŠธ๋žœ์žญ์…˜์ด ์—ฌ๋Ÿฌ ์ƒค๋“œ์— ์“ฐ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ๋ชจ๋“  ์™ธ๋ถ€ ์ฝ๊ธฐ ์ž‘์—…์ด ์ปค๋ฐ‹๋œ ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ƒค๋“œ ์ „์ฒด์— ํ‘œ์‹œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๊ณ  ์“ฐ๊ธฐ 1์ด ์ƒค๋“œ A์— ํ‘œ์‹œ๋˜์ง€๋งŒ ์“ฐ๊ธฐ 2๊ฐ€ ์ƒค๋“œ B์— ์•„์ง ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์ฝ๊ธฐ ๊ณ ๋ ค "local"์˜ ์™ธ๋ถ€ ์ฝ๊ธฐ๋Š” ์“ฐ๊ธฐ 2๋ฅผ ๋ณด์ง€ ์•Š๊ณ  ์“ฐ๊ธฐ 1์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์ด ์ค‘๋‹จ๋˜๋ฉด ํŠธ๋žœ์žญ์…˜์—์„œ ๋ฐœ์ƒํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ํ‘œ์‹œ๋˜์ง€ ์•Š๊ณ  ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠธ๋žœ์žญ์…˜์˜ ์ž‘์—…์ด ์‹คํŒจํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์ด ์ค‘๋‹จ๋˜๊ณ  ํŠธ๋žœ์žญ์…˜์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํ‘œ์‹œ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ ํ๊ธฐ๋ฉ๋‹ˆ๋‹ค.

์ค‘์š”

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ๋‹จ์ผ ๋ฌธ์„œ ์“ฐ๊ธฐ์— ๋น„ํ•ด ๋” ํฐ ์„ฑ๋Šฅ ๋น„์šฉ์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์˜ ๊ฐ€์šฉ์„ฑ์ด ํšจ๊ณผ์ ์ธ ์Šคํ‚ค๋งˆ ์„ค๊ณ„๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋น„์ •๊ทœํ™”๋œ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (๋‚ด์žฅ๋œ ๋ฌธ์„œ ๋ฐ ๋ฐฐ์—ด) ์€ ๊ณ„์†ํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ฐ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ตœ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ๋ชจ๋ธ๋งํ•˜๋ฉด ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์˜ ํ•„์š”์„ฑ์ด ์ตœ์†Œํ™”๋ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ ๊ณ ๋ ค ์‚ฌํ•ญ(์˜ˆ: ๋Ÿฐํƒ€์ž„ ์ œํ•œ ๋ฐ oplog ํฌ๊ธฐ ์ œํ•œ)์€ ํ”„๋กœ๋•์…˜ ๊ณ ๋ ค์‚ฌํ•ญ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŒ

๋‹ค์Œ๋„ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ์—ฌ๋Ÿฌ ์ž‘์—…, ์ปฌ๋ ‰์…˜, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ๋ฌธ์„œ ๋ฐ ์ƒค๋“œ ์ „๋ฐ˜์— ๊ฑธ์ณ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฑฐ๋ž˜์˜ ๊ฒฝ์šฐ:

  • ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ปฌ๋ ‰์…˜๊ณผ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํŠธ๋žœ์žญ์…˜์—์„œ ์ปฌ๋ ‰์…˜ ๋ฐ ์ธ๋ฑ์Šค ์ƒ์„ฑํ•˜๊ธฐ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

  • ํŠธ๋žœ์žญ์…˜์— ์‚ฌ์šฉ๋˜๋Š” ์ปฌ๋ ‰์…˜์€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ฐธ๊ณ 

    ์ƒค๋“œ ๊ฐ„ ์“ฐ๊ธฐ ํŠธ๋žœ์žญ์…˜์—์„œ๋Š” ์ƒˆ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•˜๋‚˜์˜ ์ƒค๋“œ์—์„œ ๊ธฐ์กด ์ปฌ๋ ‰์…˜์— ์“ฐ๊ณ  ๋‹ค๋ฅธ ์ƒค๋“œ์—์„œ ์•”์‹œ์ ์œผ๋กœ ์ƒˆ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ, MongoDB๋Š” ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ๋‘ ์ž‘์—…์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ์ œํ•œ๋œ ์ปฌ๋ ‰์…˜์—๋Š” ์“ธ (write) ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ๊ณ ์ • ์‚ฌ์ด์ฆˆ ์ปฌ๋ ‰์…˜์—์„œ ์ฝ์„ ๋•Œ๋Š” ์ฝ๊ธฐ ๊ณ ๋ ค "snapshot"์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (MongoDB 5.0๋ถ€ํ„ฐ ๋„์ž…๋จ)

  • config, admin ๋˜๋Š” local ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ปฌ๋ ‰์…˜์„ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • system.* ์ปฌ๋ ‰์…˜์— ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • explain ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง€์›๋˜๋Š” ์ž‘์—…์˜ ์ฟผ๋ฆฌ ๊ณ„ํš์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์™ธ๋ถ€์—์„œ ์ƒ์„ฑ๋œ ์ปค์„œ์˜ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ getMore์„(๋ฅผ) ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์—์„œ ์ƒ์„ฑ๋œ ์ปค์„œ์˜ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์™ธ๋ถ€์—์„œ getMore๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์˜ ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์œผ๋กœ killCursors๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    ๋˜ํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ killCursors ๋ช…๋ น์„ ์‹คํ–‰ ํ•˜๋ฉด ์„œ๋ฒ„ ๊ฐ€ ์ง€์ •๋œ ์ปค์„œ๋ฅผ ์ฆ‰์‹œ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜ ์ด ์ปค๋ฐ‹ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์—์„œ ์ง€์›๋˜์ง€ ์•Š๋Š” ์ž‘์—… ๋ชฉ๋ก์€ ์ œํ•œ๋œ ์ž‘์—…์„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŒ

ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ง์ „์— ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ปฌ๋ ‰์…˜์— ์•ก์„ธ์Šคํ•˜๋Š” ๊ฒฝ์šฐ ์“ฐ๊ธฐ ๊ณ ๋ ค "majority"๊ฐ€ ์žˆ๋Š” ๋งŒ๋“ค๊ธฐ ๋˜๋Š” ์ œ๊ฑฐ ์ž‘์—…์„ ์‹คํ–‰ํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜์ด ํ•„์š”ํ•œ ์ž ๊ธˆ์„ ํš๋“ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์„ธ์š”.

ํŒ

๋‹ค์Œ๋„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŠธ๋žœ์žญ์…˜์ด ๊ต์ฐจ ์ƒค๋“œ ์“ฐ๊ธฐ ํŠธ๋žœ์žญ์…˜(write transaction)์ด ์•„๋‹Œ ๊ฒฝ์šฐ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์—์„œ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์ด์ „์— ์ƒ์„ฑ๋œ ์ƒˆ๋กœ์šด ๋นˆ ์ปฌ๋ ‰์…˜์— ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑ.

ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค ๋•Œ

ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์— ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑ ํ•  ๋•Œ [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 ๋‹จ๊ณ„์˜ ์ง‘๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ:

    • {00}} ๋Œ€์‹  ๋‹ค์Œ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

      db.coll.aggregate([
      { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
      { $project: { _id: 0 } }
      ])
    • {00}} ๋Œ€์‹  ๋‹ค์Œ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

      db.coll.aggregate([
      { $match: { status: "A" } },
      { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
      { $project: { _id: 0 } }
      ])

    ํŒŒ์ดํ”„๋ผ์ธ์€ ๋ฌธ์„œ์— ์ปค์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    { "distinctValues" : [ 2, 3, 1 ] }

    ์ปค์„œ๋ฅผ ๋ฐ˜๋ณตํ•˜์—ฌ ๊ฒฐ๊ณผ ๋ฌธ์„œ์— ์•ก์„ธ์Šคํ•ฉ๋‹ˆ๋‹ค.

2} buildInfo,helloconnectionStatus , ๊ณผ ๊ฐ™์€ ์ •๋ณด ๋ช…๋ น(๋ฐ ๊ทธ ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ) (๋ฐ ํ•ด๋‹น ํ—ฌํผ ๋ฉ”์„œ๋“œ)์™€ ๊ฐ™์€ ์ •๋ณด ๋ช…๋ น์€ ํŠธ๋žœ์žญ์…˜์—์„œ ํ—ˆ์šฉ๋˜์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜์˜ ์ฒซ ๋ฒˆ์งธ ์—ฐ์‚ฐ์ด ๋  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์—์„œ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ์ž‘์—…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋‹ค์ค‘ ์ƒค๋“œ ์“ฐ๊ธฐ ํŠธ๋žœ์žญ์…˜์—์„œ ์ƒˆ๋กœ์šด ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๊ธฐ. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•˜๋‚˜์˜ ์ƒค๋“œ์—์„œ ๊ธฐ์กด ์ปฌ๋ ‰์…˜์— ์“ฐ๊ณ  ๋‹ค๋ฅธ ์ƒค๋“œ์— ์•”์‹œ์ ์œผ๋กœ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ MongoDB๋Š” ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ๋‘ ์ž‘์—…์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ์ปฌ๋ ‰์…˜(์˜ˆ: db.createCollection() ๋ฉ”์„œ๋“œ) ๋ฐ ์ธ๋ฑ์Šค(์˜ˆ: db.collection.createIndexes() ๋ฐ db.collection.createIndex() ๋ฉ”์„œ๋“œ)์˜ ์ƒ์„ฑ์„ "local" ์ด์™ธ์˜ ์ฝ๊ธฐ ๊ณ ๋ ค ์ˆ˜์ค€์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

  • listCollections 2} ๋ฐ ๋ช…๋ น๊ณผ ํ•ด๋‹น ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ.listIndexes

  • createUser, getParameter, count ๋“ฑ๊ณผ ํ•ด๋‹น ํ—ฌํผ์™€ ๊ฐ™์€ ๊ธฐํƒ€ ๋น„ CRUD ๋ฐ ๋น„ ์ •๋ณด ์ž‘์—…์ž…๋‹ˆ๋‹ค.

  • ๋ณ‘๋ ฌ ์ž‘์—…. ์—ฌ๋Ÿฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๋™์‹œ์— ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด bulkWrite ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์€ ์„ธ์…˜๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์„ธ์…˜๋‹น ํ•œ ๋ฒˆ์— ์ตœ๋Œ€ ํ•œ ๊ฐœ์˜ ์—ด๋ฆฐ ํŠธ๋žœ์žญ์…˜๋งŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜์˜ ๊ฐ ์ž‘์—…์€ ์„ธ์…˜๊ณผ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋“œ๋ผ์ด๋ฒ„๋ณ„ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

  • ์„ธ์…˜์ด ์ข…๋ฃŒ๋˜๊ณ  ์—ด๋ ค ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์˜ ์ž‘์—…์—๋Š” ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ธฐ๋ณธ ์„ค์ •์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ธฐ๋ณธ ์„ค์ •์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ์„ค์ •์ด ์ง€์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์€ ์„ธ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ์„ค์ •์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ๋ฐ ์„ธ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ์„ค์ •์ด ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์€ ํด๋ผ์ด์–ธํŠธ ์ˆ˜์ค€ ์ฝ๊ธฐ ์„ค์ •์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ˆ˜์ค€ ์ฝ๊ธฐ ์„ค์ •์€ primary์ž…๋‹ˆ๋‹ค.

์ฝ๊ธฐ ์ž‘์—…์ด ํฌํ•จ๋œ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ์ฝ๊ธฐ ์„ค์ • primary(์„)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ํŠธ๋žœ์žญ์…˜์˜ ๋ชจ๋“  ์ž‘์—…์€ ๋™์ผํ•œ ๊ตฌ์„ฑ์›์œผ๋กœ ๋ผ์šฐํŒ…๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์˜ ์ž‘์—…์€ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ปฌ๋ ‰์…˜ ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ˆ˜์ค€์—์„œ ์„ค์ •๋œ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๋Š” ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€์˜ ์ฝ๊ธฐ ๋ฌธ์ œ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ๋ฐ ์„ธ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค (read concern)๋Š” ํ”„๋ผ์ด๋จธ๋ฆฌ ์ฝ๊ธฐ์—์„œ "local"์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๋„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŠธ๋žœ์žญ์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ๊ธฐ ๊ณ ๋ ค ์ˆ˜์ค€์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • ์ฝ๊ธฐ ๊ณ ๋ ค "local"๋Š” ๋…ธ๋“œ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ตœ๊ทผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๋กค๋ฐฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ณต์ œ๋ณธ ์„ธํŠธ ์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜ ์ด ์ฝ๊ธฐ ๊ณ ๋ ค (read concern) local ์„(๋ฅผ) ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ํŠธ๋žœ์žญ์…˜ ์ด ์—ด๋ฆฐ ์  ์— ์Šค๋ƒ…์ƒท ์—์„œ ์ฝ๋Š” ์ž‘์—…์—์„œ ๋” ๊ฐ•๋ ฅํ•œ ์ฝ๊ธฐ ๊ฒฉ๋ฆฌ ๊ฐ€ ๊ด€์ฐฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์ด ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์— ์žˆ๋Š” ๊ฒฝ์šฐ, "local" ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒค๋“œ ์ „์ฒด์˜ ๋™๋ฆฌํ•œ ์Šค๋ƒ…์ƒท ๋ณด๊ธฐ์—์„œ ๋‚˜์˜จ ๊ฒƒ์ž„์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์Šค๋ƒ…์ƒท ๊ฒฉ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ "snapshot" ์ฝ๊ธฐ ๊ณ ๋ ค๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ปฌ๋ ‰์…˜๊ณผ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปฌ๋ ‰์…˜์ด๋‚˜ ์ธ๋ฑ์Šค๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ, ํŠธ๋žœ์žญ์…˜์€ ๋ฐ˜๋“œ์‹œ ์ฝ๊ธฐ ๊ณ ๋ ค "local"(์„)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ปฌ๋ ‰์…˜์„ ์•”์‹œ์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ฝ๊ธฐ ๊ณ ๋ ค๋ฅผ ํŠธ๋žœ์žญ์…˜์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์ด ์“ฐ๊ธฐ ๊ณ ๋ ค "majority"๋กœ ์ปค๋ฐ‹๋˜๋ฉด ์ฝ๊ธฐ ๊ณ ๋ ค "majority"๋Š” ๋ณต์ œ๋ณธ ์„ธํŠธ ๋ฉค๋ฒ„์˜ ๊ณผ๋ฐ˜์ˆ˜๊ฐ€ ์ธ์ •ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด๋Š” ๋กค๋ฐฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ฝ๊ธฐ ๊ณ ๋ ค "majority"๋Š” ์ฝ๊ธฐ ์ž‘์—…์ด ๊ณผ๋ฐ˜์ˆ˜๊ฐ€ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š”๋‹ค๋Š” ๋ณด์žฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ์˜ ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ์šฐ, ์ฝ๊ธฐ ๊ณ ๋ ค "majority"๋Š” ์ƒค๋“œ ์ „์ฒด์—์„œ ๋™์ผํ•œ ์Šค๋ƒ…์ƒท ๋ทฐ์˜ ๋ฐ์ดํ„ฐ์ž„์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์Šค๋ƒ…์ƒท ๊ฒฉ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ฝ๊ธฐ ๊ณ ๋ ค "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)์™€ ์„ธ์…˜ ์ˆ˜์ค€ ์“ฐ๊ธฐ ๊ณ ๋ ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์“ฐ๊ธฐ ๊ณ ๋ ค๋Š” ๊ธฐํด๋ผ์ด์–ธํŠธ ์ˆ˜์ค€ ์“ฐ๊ธฐ ๊ณ ๋ ค๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŒ

๋‹ค์Œ๋„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŠธ๋žœ์žญ์…˜์€ ๋‹ค์Œ์„ ํฌํ•จํ•œ ๋ชจ๋“  ์“ฐ๊ธฐ ๊ณ ๋ ค w ๊ฐ’์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • ์“ฐ๊ธฐ ๊ณ ๋ ค w: 1์€ ์ปค๋ฐ‹์ด ํ”„๋ผ์ด๋จธ๋ฆฌ์— ์ ์šฉ๋œ ํ›„ ์Šน์ธ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    ์ค‘์š”

    w: 1๋กœ ์ปค๋ฐ‹ํ•  ๋•Œ ํŽ˜์ผ์˜ค๋ฒ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • w: 1 ์“ฐ๊ธฐ ๊ณ ๋ ค๋กœ "majority" ์ปค๋ฐ‹ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์ฝ๊ธฐ ์ž‘์—…์ด ๋Œ€๋‹ค์ˆ˜ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ณด์žฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • w: 1 ์“ฐ๊ธฐ ๊ณ ๋ ค๋กœ ์ปค๋ฐ‹ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ "snapshot" ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์ฝ๊ธฐ ์ž‘์—…์ด ๋Œ€๋‹ค์ˆ˜ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ์˜ ์Šค๋ƒ…์ƒท์„ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๋ณด์žฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์“ฐ๊ธฐ ๊ณ ๋ ค w: "majority"๋Š” ํˆฌํ‘œ ๋…ธ๋“œ ๊ณผ๋ฐ˜์ˆ˜์—๊ฒŒ ์ปค๋ฐ‹์ด ์ ์šฉ๋œ ํ›„ ์Šน์ธ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • w: "majority" ์“ฐ๊ธฐ ๊ณ ๋ ค๋กœ ์ปค๋ฐ‹ํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ "majority" ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ์ž‘์—…์ด ๋Œ€๋‹ค์ˆ˜ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์—ˆ์Œ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ์šฐ ๋Œ€๋ถ€๋ถ„ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ด ๋ณด๊ธฐ๋Š” ์ƒค๋“œ ์ „์ฒด์—์„œ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • w: "majority" 2} ์“ฐ๊ธฐ ๊ณ ๋ ค๋กœ ์ปค๋ฐ‹ํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜ ์ˆ˜์ค€ "snapshot" ์ฝ๊ธฐ ๊ณ ๋ ค๋Š” ์ž‘์—…์ด ๋Œ€๋‹ค์ˆ˜ ์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ์˜ ๋™๊ธฐํ™”๋œ ์Šค๋ƒ…์ƒท์—์„œ ์ฝ์€ ๊ฒƒ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ 

ํŠธ๋žœ์žญ์…˜์— ์ง€์ •๋œ ์“ฐ๊ธฐ ๊ณ ๋ ค์™€ ๊ด€๊ณ„์—†์ด, ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ์ปค๋ฐ‹ ์ž‘์—…์—๋Š” {w: "majority", j: true} ์“ฐ๊ธฐ ๊ณ ๋ ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ผ๋ถ€ ๋ถ€๋ถ„์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„ ๋งค๊ฐœ๋ณ€์ˆ˜ coordinateCommitReturnImmediatelyAfterPersistingDecision๋Š” ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ๊ฒฐ์ •์ด ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜๋˜๋Š” ์‹œ๊ธฐ๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

์ด ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” MongDB 5.0์—์„œ ๊ธฐ๋ณธ๊ฐ’์ด true๋กœ ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. MongoDB 6.1์—์„œ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด false๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

coordinateCommitReturnImmediatelyAfterPersistingDecision์ด false๊ฐ€ ๋˜๋ฉด ์ƒค๋“œ ํŠธ๋žœ์žญ์…˜ ์ฝ”๋””๋„ค์ดํ„ฐ๋Š” ๋ชจ๋“  ๋ฉค๋ฒ„๊ฐ€ ๋‹ค์ค‘ ๋ฌธ์„œ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹์„ ์Šน์ธํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ ๋‹ค์Œ ์ปค๋ฐ‹ ๊ฒฐ์ •์„ ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

"majority" ๋‹จ์ผ ๋ฌธ์„œ ๋ฐ ๋‹ค์ค‘ ๋ฌธ์„œ ์“ฐ๊ธฐ์— ์“ฐ๊ธฐ ๊ณ ๋ ค (write concern) ์ง€์ •ํ•˜๊ณ  ์ž‘์—…์ด ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— ๊ณ„์‚ฐ๋œ ๊ณผ๋ฐ˜์ˆ˜ ์ด์ƒ์˜ ๋ณต์ œ๋ณธ ์„ธํŠธ ๋ฉค๋ฒ„์— ๋ณต์ œํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฒฐ๊ตญ ๋ณต์ œ๋˜๊ฑฐ๋‚˜ ๋กค๋ฐฑ๋ฉ๋‹ˆ๋‹ค. ๋ฅผ wtimeout ์ฐธ์กฐํ•˜์„ธ์š”.

ํŠธ๋žœ์žญ์…˜์— ์ง€์ •๋œ ์“ฐ๊ธฐ ๊ณ ๋ ค์— ๊ด€๊ณ„์—†์ด ๋“œ๋ผ์ด๋ฒ„๋Š” commitTransaction (์„)๋ฅผ ์žฌ์‹œ๋„ํ•  ๋•Œ ์“ฐ๊ธฐ ๊ณ ๋ ค๋กœ w: "majority"(์„)๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ๊ณ ๋ ค ์‚ฌํ•ญ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ์˜ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•ด์„œ๋Š” ํ”„๋กœ๋•์…˜ ๊ณ ๋ ค ์‚ฌํ•ญ์„ ์ฐธ์กฐํ•˜์„ธ์š”. ๋˜ํ•œ ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๊ฒฝ์šฐ ํ”„๋กœ๋•์…˜ ๊ณ ๋ ค ์‚ฌํ•ญ(์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ)์„ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ณต์ œ๋ณธ ์„ธํŠธ ์— ์ค‘์žฌ์ž ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํŠธ๋žœ์žญ์…˜ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒค๋“œ ํ‚ค ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ค‘์žฌ์ž๋Š” ๋ฉ€ํ‹ฐ ์ƒค๋“œ ํŠธ๋žœ์žญ์…˜์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ž‘์—…์— ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์“ฐ๊ธฐ ์ž‘์—…์ด ์—ฌ๋Ÿฌ ์ƒค๋“œ์— ๊ฑธ์ณ ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์€ ํŠธ๋žœ์žญ์…˜ ์ž‘์—… ์ค‘ ์–ด๋–ค ๊ฒƒ์ด๋“  ์ค‘์žฌ์ž๊ฐ€ ํฌํ•จ๋œ ์ƒค๋“œ์—์„œ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋Š” ๊ฒฝ์šฐ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.

writeConcernMajorityJournalDefault๊ฐ€ false๋กœ ์„ค์ •๋œ ์ƒค๋“œ๊ฐ€ ์žˆ๋Š” ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (์˜ˆ: ์ธ๋ฉ”๋ชจ๋ฆฌ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๋Š” ํˆฌํ‘œ ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š” ์ƒค๋“œ)

์ฐธ๊ณ 

ํŠธ๋žœ์žญ์…˜์— ์ง€์ •๋œ ์“ฐ๊ธฐ ๊ณ ๋ ค์™€ ๊ด€๊ณ„์—†์ด, ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ์ปค๋ฐ‹ ์ž‘์—…์—๋Š” {w: "majority", j: true} ์“ฐ๊ธฐ ๊ณ ๋ ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ผ๋ถ€ ๋ถ€๋ถ„์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ ๋ฐ ์ง€ํ‘œ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋‹ค์Œ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์†Œ์Šค
๋ฐ˜ํ™˜

ํŠธ๋žœ์žญ์…˜ ์ธก์ •ํ•ญ๋ชฉ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Some serverStatus response fields are not returned on MongoDB Atlas M0/M2/M5 clusters or Flex clusters. For more information, see Limited Commands in the MongoDB Atlas documentation.

$currentOp ์ง‘๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ

๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

  • ์ž‘์—…์ด ํŠธ๋žœ์žญ์…˜์˜ ์ผ๋ถ€์ธ ๊ฒฝ์šฐ $currentOp.transaction.

  • ํŠธ๋žœ์žญ์…˜์˜ ์ผ๋ถ€๋กœ ์ž ๊ธˆ์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ๋น„ํ™œ์„ฑ ์„ธ์…˜์— ๋Œ€ํ•œ ์ •๋ณด์ž…๋‹ˆ๋‹ค.

  • ์—ฌ๋Ÿฌ ์ƒค๋“œ์— ๋Œ€ํ•œ ์“ฐ๊ธฐ์™€ ๊ด€๋ จ๋œ ์ƒค๋“œ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ $currentOp.twoPhaseCommitCoordinator ์ง€ํ‘œ์ž…๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

  • ์ž‘์—…์ด ํŠธ๋žœ์žญ์…˜์˜ ์ผ๋ถ€์ธ ๊ฒฝ์šฐ currentOp.transaction.

  • ์—ฌ๋Ÿฌ ์ƒค๋“œ์— ๋Œ€ํ•œ ์“ฐ๊ธฐ์™€ ๊ด€๋ จ๋œ ์ƒค๋“œ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ currentOp.twoPhaseCommitCoordinator ์ง€ํ‘œ์ž…๋‹ˆ๋‹ค.

mongod ๋ฐ mongos ๋กœ๊ทธ ๋ฉ”์‹œ์ง€

TXN ๋กœ๊ทธ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Š๋ฆฐ ํŠธ๋žœ์žญ์…˜(operationProfiling.slowOpThresholdMs ์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ํŠธ๋žœ์žญ์…˜)์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋””ํ”Œ๋กœ์ด๋จผํŠธ์˜ ๋ชจ๋“  ๋ฉค๋ฒ„์— ๋Œ€ํ•œ FeatureCompatibilityVersion์ด ์ตœ์†Œํ•œ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐํฌ
์ตœ์†Œ featureCompatibilityVersion

๋ณต์ œ๋ณธ ์„ธํŠธ

4.0

์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ

4.2

๋ฉค๋ฒ„์˜ fCV๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด ํ•ด๋‹น ๋ฉค๋ฒ„์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์„ธ์š”.

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

์ž์„ธํ•œ ๋‚ด์šฉ์€ setFeatureCompatibilityVersion ๋„์›€๋ง ํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ณต์ œ๋ณธ ์„ธํŠธ์™€ ์ƒค๋”ฉ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์ง€์›๋˜๋Š” ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์€ ๋‹ค์Œ ์กฐ๊ฑด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ”„๋ผ์ด๋จธ๋ฆฌ๋Š” WiredTiger ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๋ณด์กฐ ๋ฉค๋ฒ„๋Š” ์™€์ด์–ด๋“œํƒ€์ด๊ฑฐ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„ ๋˜๋Š” ์ธ๋ฉ”๋ชจ๋ฆฌ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ 

writeConcernMajorityJournalDefault๊ฐ€ false์œผ๋กœ ์„ค์ •๋œ ์ƒค๋“œ๊ฐ€ ์žˆ๋Š” ์ƒค๋“œ ํด๋Ÿฌ์Šคํ„ฐ (์˜ˆ: ์ธ๋ฉ”๋ชจ๋ฆฌ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๋Š” ํˆฌํ‘œ ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š” ์ƒค๋“œ)์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

MongoDB 5.2(๋ฐ 5.0.4)๋ถ€ํ„ฐ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

  • ์ฟผ๋ฆฌ๊ฐ€ ๋ถ„ํ• ๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์•ก์„ธ์Šคํ•  ๋•Œ ์ฒญํฌ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋˜๋Š” DDL ์ž‘์—…์€ ์ปฌ๋ ‰์…˜์— ๋Œ€ํ•œ ์ค‘์š”ํ•œ ์„น์…˜์„ ๋ณด์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ƒค๋“œ๊ฐ€ ํŠธ๋žœ์žญ์…˜ ๋‚ด ์ค‘์š” ์„น์…˜๊นŒ์ง€ ๋Œ€๊ธฐํ•˜๋Š” ์‹œ๊ฐ„์„ ์ œํ•œํ•˜๋ ค๋ฉด metadataRefreshInTransactionMaxWaitBehindCritSecMS ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.