Introduction to the

The transaction of mongodb is realized by the client session connected to mongodb. The process of transaction execution is roughly to establish a session and start the transaction through session startTransaction. If a series of transactions are completed, CommitTransaction completes the transaction and ends the current transaction session. If any of the series of transactions fails, abortTransaction aborts the transaction, internally rolls back the completed task to the time before the modification, and terminates the current transaction session.

session = client.startSession(); 
session.startTransaction();
session.commitTransaction();
session.abortTransaction();
session.endSession();
Copy the code

Scene description

At present, there are two users, user A has A balance of 50 RMB, user B has A balance of 10 RMB, and user A transfers 10 RMB to USER B. The scene is set that the transfer is safe, the network is smooth, no hacking interception, no accident, the transfer is successful, at this moment, user A has A balance of 40 RMB, and user B has A balance of 20 RMB. A felt safe and transferred money to B. A forgot the balance and transferred 50 to B, but it made A mistake.

In the case of no transactions, the operation database looks like this, the balance of 1.A account is -50, and 2.B account is increased by 50. When the balance of A is insufficient or the network error occurs after the successful operation of account A, the amount of account B cannot be modified correctly.

In the case of A transaction, even if an error occurs after manipulating the amount of account A, the transaction reverses the entire transfer process to before the modification.

Download Mongodb4 and unpack it

www.mongodb.com/download-ce…

Wget https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.0.tgz tar - XZVF mongo osx - SSL - x86_64-4.0.0. TGZcdMongo osx - SSL - x86_64-4.0.0Copy the code

!!!!!!!!! Transaction only applies to Replica Set, so build mongodb Replica Set first

Start multiple mongodb instances

// Create data directory mkdir -p data/1301 mkdir -p data/1302 mkdir -p data/1303 // Start three mongodb instances./bin/mongod --replSet shard1 --dbpath=./data/1301 --port=1301 ./bin/mongod --replSet shard1 --dbpath=./data/1302 --port=1302 ./bin/mongod --replSet shard1 --dbpath=./data/1303 --port=1303Copy the code

// configure the replication set./ /bin/mongo --port 1301 rsconf = {_id:"shard1", members: [ { _id: 0, host: "127.0.0.1:1301" } ] }
rs.initiate( rsconf )
rs.add("127.0.0.1:1302")
rs.add("127.0.0.1:1303")
Copy the code

Rs.ismaster () rs.ismaster ()Copy the code

coding

mkdir mongodb4
cd mongodb4
npm init
npm i mongodb -S
vi app.js
Copy the code
//app.js

(async function()  {

  / / DB connection
  const { MongoClient } = require('mongodb');
  const uri = 'mongodb://localhost:1301/dbfour';
  const client = await MongoClient.connect(uri, { useNewUrlParser: true });

  const db = client.db();
  await db.dropDatabase();
  console.log(Select * from dbfour where dbfour = 'n';)

  // Insert two accounts and top up some money
  await db.collection('Account').insertMany([
    { name: 'A'.balance: 50 },
    { name: 'B'.balance: 10}]);console.log('(2) insertMany, A recharge 50, B recharge 10\n')


  await transfer('A'.'B'.10); / / success
  console.log(Then A transfers 10\n' to B)

  try {
    // Transfer failed due to insufficient balance
    console.log('(4) A transfers again to B 50\n')
    await transfer('A'.'B'.50);

  } catch (error) {
    //error.message; // "Insufficient funds: 40"
    console.log(error.message)
    console.log('\n(5) A balance is not enough, so the transfer operation is not successful ')}// Transfer logic
  async function transfer(from, to, amount) {
    const session = client.startSession();
    session.startTransaction();
    try {
      const opts = { session, returnOriginal: false };
      const A = await db.collection('Account').
        findOneAndUpdate({ name: from }, { $inc: { balance: -amount } }, opts).
        then(res= > res.value);
      if (A.balance < 0) {
        // If the balance of A is insufficient, the transfer fails to terminate the transaction
        // 'session.abortTransaction()' will cancel the 'findOneAndUpdate()' operation above
        throw new Error('Insufficient funds: ' + (A.balance + amount));
      }

      const B = await db.collection('Account').
        findOneAndUpdate({ name: to }, { $inc: { balance: amount } }, opts).
        then(res= > res.value);

      await session.commitTransaction();
      session.endSession();
      return { from: A, to: B };
    } catch (error) {
      // If an error occurs, abort all transactions and fall back to before the modification
      await session.abortTransaction();
      session.endSession();
      throw error; // make the caller catch error}}}) ()Copy the code

View the results

node app.js
Copy the code