[mongodb] transaction

Time:2021-10-16

 

summary

  • Mongodb 4.0 supports multi document transactions for replica sets
  • Mongodb 4.2 supports multi document transactions in fragmented clusters

A single server does not support transactions, so to learn transactions, you need to build a replica set / fragment cluster

In addition, it should be noted that a single document operation is an atomic operation, while mongodb is a document database. On a single document, the format of object / array can be embedded to maintain the relationship between data, rather than using multiple sets to maintain the relationship between data. Due to this feature of mongodb, a single document operation eliminates many transaction requirements.

 

Build replica set

Here is the simplest way to build a replica set

one   Start multiple mongod instances. Here, use the CMD command to start

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"

Parameter description

  • Replset: sets the replica set name
  • Port: set the port. Because I am a stand-alone computer, I can only set different ports
  • Dbpath: data file path. Note: the folder must exist and mongod will not be created automatically
  • Logpath: the name of the log file, which does not need to be created in advance. If mongod does not exist, it will be created automatically

two    To connect any instance, select 27017 as the default port

mongo

 

three   Start replica set

rs.initiate({
    _id: "rs0",
    members: [
        { _id: 0, host: "127.0.0.1:27017" },
        { _id: 1, host: "127.0.0.1:27018" }
    ]
})

Parameter description

  • _ ID: replica set name, which is the name specified when starting the instance
  • Members: This is all members_ ID ID of each member, integer type [0255]

Return field “OK”: 1 indicates that the creation is successful

Rs.initiate ({}), except for a few necessary ones, the default configuration is used to start. For more configuration parameters, please refer toreplica-configuration

 

four   View current configuration information

rs.conf()

 

five   View replica set information

rs.status()

 

At this point, the replica set is built

 

affair

1. Connect replica sets

mongo mongodb://127.0.0.1:27017,127.0.0.1:27018/?replicaSet=rs0

You can directly connect to the instance of the primary replica, or you can use this URL to automatically connect to the primary replica (the latter is recommended)

 

two   Prepare 2 pieces of data

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 } });

 

Test normal submission

Simulate a deduction action, in which the deduction and flow are in one transaction

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();

 

View balance

db.balance.aggregate([
    { $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
    { $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);

As a result, you can see that the balance is deducted and there is an additional running water

{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }

 

 

Test failure rollback

Add an operation to insert a nonexistent set in the transaction to make the transaction report an error

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() });    // Add more than one nonexistent table
} catch (error) {
    session.abortTransaction();
    throw error;
}
session.commitTransaction();
session.endSession();

 

An error message is returned indicating that the transaction has been interrupted

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)
                }
        }
} :
[email protected]/mongo/shell/utils.js:25:13
doas[email protected]/mongo/shell/assert.js:18:14
[email protected]/mongo/shell/assert.js:583:17
[email protected]/mongo/shell/assert.js:673:16
[email protected]/mongo/shell/session.js:971:17
@(shell):1:1

Then view the current balance

db.balance.aggregate([
    { $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
    { $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);

As you can see, the balance and running water have not changed.

{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }

 

 Reference articles


Replication — MongoDB Manual

Transactions — MongoDB Manual

Please indicate the source of forwarding: https://www.cnblogs.com/WilsonPan/p/12708710.html

Recommended Today

SQL statement of three-level linkage of provinces, cities and counties

The first is the table creation statement Copy codeThe code is as follows: CREATE TABLE `t_address_province` ( `id` INT AUTO_ Increment primary key comment ‘primary key’,`Code ` char (6) not null comment ‘province code’,`Name ` varchar (40) not null comment ‘province name’)Engine = InnoDB default charset = utf8 comment = ‘province information table’; CREATE TABLE […]