【Mongodb】トランザクション
18646 ワード
概要
単一のサーバではトランザクションの使用はサポートされていないため、トランザクションを学習するには、レプリカセット/スライスクラスタを構築する必要があります.
また、単一のドキュメント操作は原子操作であり、mongodbはドキュメント型データベースであり、単一のドキュメントには、複数のセットを使用してデータ間の関係を維持するのではなく、オブジェクト/配列というフォーマットを埋め込むことができます.mongodbのこのような特性のため、単一のドキュメント操作はトランザクションを必要とする多くのニーズを排除します.
レプリカセットの作成
次に、最も簡単な方法でレプリカセットを構築します.
1.複数のmongodインスタンスを起動します.ここではcmdコマンドを使用して起動します.
start "Mongodb Service - 27017" /min mongod --port 27017 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27017" --logpath "F:\Database\Mongodb\Log\mongod.27017.log"
start "Mongodb Service - 27018" /min mongod --port 27018 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27018" --logpath "F:\Database\Mongodb\Log\mongod.27018.log"
パラメータの説明
2.任意のインスタンスを接続し、ここでは27017というデフォルトポートを選択する
mongo
3.レプリカセットの起動
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "127.0.0.1:27017" },
{ _id: 1, host: "127.0.0.1:27018" }
]
})
パラメータの説明
rs.initiate({})は、デフォルトの構成を使用して起動する必要があるいくつかを除いて、replica-configurationを参照してください.
4.現在の構成情報の表示
rs.conf()
5.レプリカセット情報の表示
rs.status()
これでコピーセットが完成します
取引
1.レプリカセットの接続
mongo mongodb://127.0.0.1:27017,127.0.0.1:27018/?replicaSet=rs0
プライマリ・レプリカのインスタンスを直接接続したり、url形式でプライマリ・レプリカを自動的に接続したりできます(後者を推奨します).
2.データを2つ用意する
db.balance.insert({ name: "Wilson", balance: 100 }, { writeConcern: { w: "majority", wtimeout: 2000 } });
db.record.insert({ name: "Wilson", change: 100, balance: 100, }, { writeConcern: { w: "majority", wtimeout: 2000 } });
正常なコミットのテスト
お金を引く動作をシミュレートします.その中で、控除と流水は事務の中にあります.
session = db.getMongo().startSession({ readPreference: { mode: "primary" } });
balanceCol = session.getDatabase("mongo").balance;
recordCol = session.getDatabase("mongo").record;
session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
try {
balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": 50 } });
recordCol.insertOne({ "name": "Wilson", change: -50, balance: 50 });
} catch (error) {
session.abortTransaction();
}
session.commitTransaction();
session.endSession();
残高の表示
db.balance.aggregate([
{ $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
{ $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);
結局、残高が引かれて流れが1本増えたのが見えます
{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }
テスト失敗ロールバック
トランザクションに存在しないコレクションを挿入する操作を追加し、トランザクションをエラーにします.
session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
try {
balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": -50 } });
recordCol.insertOne({ "name": "Wilson", change: -50, balance: 0 });
session.getDatabase("mongo").user.insert({ "time": new Date() }); //
} catch (error) {
session.abortTransaction();
throw error;
}
session.commitTransaction();
session.endSession();
エラーメッセージを返し、トランザクションが中断されたことを示します.
2020-04-15T21:37:05.576+0800 E QUERY [js] uncaught exception: Error: command failed: {
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp(1586957825, 1),
"ok" : 0,
"errmsg" : "Transaction 0 has been aborted.",
"code" : 251,
"codeName" : "NoSuchTransaction",
"$clusterTime" : {
"clusterTime" : Timestamp(1586957825, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:583:17
assert.commandWorked@src/mongo/shell/assert.js:673:16
commitTransaction@src/mongo/shell/session.js:971:17
@(shell):1:1
再查看当前余额情况
db.balance.aggregate([ { $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } }, { $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } }, ]);
残高も流水も変わっていないことがわかります.{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }
参考記事
Replication — MongoDB Manual
Transactions — MongoDB Manual
転送先は出典を明記してください.https://www.cnblogs.com/WilsonPan/p/12708710.html