---
title: mongodb transaction
tags: mongodb, transaction, yoctol, kurator
---
# mongodb transaction
# set up replica set
Download the docker-compose settings
`$ curl -sSL https://raw.githubusercontent.com/bitnami/bitnami-docker-mongodb/master/docker-compose-replicaset.yml > docker-compose.yml`
```
version: '2'
services:
mongodb-primary:
image: 'bitnami/mongodb:latest'
environment:
- MONGODB_ADVERTISED_HOSTNAME=mongodb-primary
- MONGODB_REPLICA_SET_MODE=primary
- MONGODB_ROOT_PASSWORD=password123
- MONGODB_REPLICA_SET_KEY=replicasetkey123
volumes:
- 'mongodb_master_data:/bitnami'
mongodb-secondary:
image: 'bitnami/mongodb:latest'
depends_on:
- mongodb-primary
environment:
- MONGODB_ADVERTISED_HOSTNAME=mongodb-secondary
- MONGODB_REPLICA_SET_MODE=secondary
- MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary
- MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017
- MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123
- MONGODB_REPLICA_SET_KEY=replicasetkey123
mongodb-arbiter:
image: 'bitnami/mongodb:latest'
depends_on:
- mongodb-primary
environment:
- MONGODB_ADVERTISED_HOSTNAME=mongodb-arbiter
- MONGODB_REPLICA_SET_MODE=arbiter
- MONGODB_INITIAL_PRIMARY_HOST=mongodb-primary
- MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017
- MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=password123
- MONGODB_REPLICA_SET_KEY=replicasetkey123
volumes:
mongodb_master_data:
driver: local
```
and run docker-compose using:
`$ docker-compose up --detach`
# Mongodb transaction
transaction before mongodb 4.0:
https://juejin.im/post/5ace2f935188255566700f19
transaction in mongodb 4.0 or later version:
```
db.accounts.insert(
[
{ _id: "A", balance: 1000, pendingTransactions: [] },
{ _id: "B", balance: 1000, pendingTransactions: [] }
]
)
db.transactionRecords.insert(
{ _id: 1, source: "A", destination: "B", value: 100, state: "initial", lastModified: new Date() }
)
// Start a session.
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
accountsCollection = session.getDatabase("test").accounts;
transactionRecordsCollection = session.getDatabase("test").transactionRecords;
// Start a transaction
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
// Operations inside the transaction
try {
accountsCollection.updateOne( { _id: "A", }, { $set: { balance: 900 } } );
accountsCollection.updateOne( { _id: "B", }, { $set: { balance: 1100 } } );
transactionRecordsCollection.updateOne( { _id: 1, }, {
$set: { state: "done" },
$currentDate: { lastModified: true }
});
} catch (error) {
// Abort transaction on error
session.abortTransaction();
throw error;
}
// Commit the transaction using write concern set at transaction start
session.commitTransaction();
session.endSession();
```
mongodb 4.0 有了新的 Multi-document transactions,在這之前 mongodb 只保證單一檔案的寫入 atomicity,既使是 batchInsert 也沒有保證寫入是同時完成的。所以使用者只能自行實作 transaction 機制,讓存取 db 的邏輯變得更加複雜。
利用新的 Multi-document transactions 可以像 relational db 一樣輕鬆做到保證跨 document、跨 collection、甚至是跨 db 的操作能夠一併完成,並且可以定義 read preference、read concern、write concern(類似 relational db 的 isolation level)。
在 mongodb 4.2 更是支援了 sharded clusters 的 transaction。
# Read Concern
在 transaction 過程中,僅適用 transaction level read concern,所有設定在 collection 以及 database level 的 read concern 設定都會被忽略;你可以在 startTransaction 時設定 readConcern,若未設定則會自動套用 session-level read concern;若 startSession 時未設定,則會自動套用 client-level 的 read concern,[預設情況下 client-level 的 read concern 是 local](https://docs.mongodb.com/manual/reference/mongodb-defaults/#read-concern)
- local
- Read concern "local" returns the most recent data available from the node but can be rolled back.
- 接近 Read Uncommitted Isolation,可能會造成 Dirty Read 等等問題
- majority
- Read concern "majority" returns data that has been acknowledged by a majority of the replica set members (i.e. data cannot be rolled back) if the transaction commits with write concern “majority”.
- If the transaction does not use write concern “majority” for the commit, the "majority" read concern provides no guarantees that read operations read majority-committed data.
- snapshot (is only available for multi-document transactions)
- Read concern "snapshot" returns data from a snapshot of majority committed data if the transaction commits with write concern “majority”.
- If the transaction does not use write concern “majority” for the commit, the "snapshot" read concern provides no guarantee that read operations used a snapshot of majority-committed data.
- 可以避免類似 Phantom read 的問題
# Write Concern
Transaction 的 write concern 只適用在 commit write operation 的時候,transaction 過程中的所有 write operation 無視 write concern(對 write operation 設定 write concern 會噴錯,因為 commit 時才算是真正寫入)
你可以在 startTransaction 時設定 writeConcern,若未設定則會自動套用 session-level write concern;若 startSession 時未設定,則會自動套用 client-level 的 write concern,[預設情況下 client-level 的 write concern 是 w: 1](https://docs.mongodb.com/manual/reference/mongodb-defaults/#write-concern)。
- w: 1
- Write concern w: 1 returns acknowledgement after the commit has been applied to the primary.
- When you commit with w: 1, your transaction can be rolled back if there is a failover.
- When you commit with w: 1 write concern, transaction-level "majority" read concern provides no guarantees that read operations in the transaction read majority-committed data.
- When you commit with w: 1 write concern, transaction-level "snapshot" read concern provides no guarantee that read operations in the transaction used a snapshot of majority-committed data.
- w: "majority"
- Write concern w: "majority" returns acknowledgement after the commit has been applied to a majority (M) of voting members; i.e. the commit has been applied to the primary and (M-1) voting secondaries.
- When you commit with w: "majority" write concern, transaction-level "majority" read concern guarantees that operations have read majority-committed data.
- When you commit with w: "majority" write concern, transaction-level "snapshot" read concern guarantees that operations have from a synchronized snapshot of majority-committed data.
# Read Preference
- primary
refs:
https://docs.mongodb.com/manual/core/causal-consistency-read-write-concerns/
https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/
https://www.mongodb.com/blog/post/quick-start-nodejs--mongodb--how-to-implement-transactions