mongoDB的事务

官网传送门:

https://docs.mongodb.com/manual/core/replica-set-write-concern/

https://docs.mongodb.com/manual/core/transactions/#read-concern-write-concern-read-preference

什么是 writeConcern ?

writeConcern 决定一个写操作落到多少个节点上才算成功。writeConcern 的取值包括:
0:发起写操作,不关心是否成功;
1~集群最大数据节点数:写操作需要被复制到指定节点数才算成功;默认是1。
majority:写操作需要被复制到大多数节点上才算成功。

• all:写入所有节点才算成功。
发起写操作的程序将阻塞到写操作到达指定的节点数为止


默认情况 w:“1”

 mongoDB的事务

大多数节点确认(即一半以上节点)   w: “majority” 

mongoDB的事务

全部节点确认 w: “all”

mongoDB的事务

j:true

 writeConcern 可以决定写操作到达多少个节点才算成功,journal 则定义如何才算成
功。取值包括:
true: 写操作落到 journal 文件中才算成功;
false: 写操作到达内存即算作成功。

数据库数据写入的顺序  数据在内存中先写日志文件(journal 中落地持久化日志文件),再写数据文件
mongoDB的事务

 mongoDB shell中使用

db.test.insert( {count: 1}, {writeConcern: {w: "majority"}})
db.test.insert( {count: 1}, {writeConcern: {w: 3 }})
db.test.insert( {count: 1}, {writeConcern: {w: 4 }})

readPreference与readConcern

readPreference 设置 分布式数据库从哪里读

readConcern 什么样的数据可以读

readPreference 

readPreference 决定使用哪一个节点来满足正在发起的读请求。可选值包括:

primary: 只选择主节点;

primaryPreferred:优先选择主节点,如果不可用则选择从节点;

secondary:只选择从节点;

secondaryPreferred:优先选择从节点,如果从节点不可用则选择主节点;

nearest:选择最近的节点;

mongoDB的事务

 场景举例:大量高并发读取的数据场景可以选择从节点,写入数据的时候,用主节点。

readPreference的 配置方式

通过 MongoDB 的连接串参数:
• mongodb://host1:27107,host2:27107,host3:27017/?replicaSet=rs&readPreference=secondary
通过 MongoDB 驱动程序 API:
• MongoCollection.withReadPreference(ReadPreference readPref)
Mongo Shell:
• db.collection.find({}).readPref( “secondary” )

readConcern

在 readPreference 选择了指定的节点后,readConcern 决定这个节点上的数据哪些是可读的,类似于关系数据库的隔离级别。可选值包括:
available:读取所有可用的数据;
local:读取所有可用且属于当前分片的数据;
majority:读取在大多数节点上提交完成的数据;
linearizable:可线性化读取文档;
snapshot:读取最近快照中的数据;

在复制集中 local 和 available 是没有区别的。两者的区别主要体现在分片集上。考虑以下场景:
• 一个 chunk x 正在从 shard1 向 shard2 迁移;
• 整个迁移过程中 chunk x 中的部分数据会在 shard1 和 shard2 中同时存在,但源分片 shard1仍然是chunk x 的负责方:
  所有对 chunk x 的读写操作仍然进入 shard1;
  config 中记录的信息 chunk x 仍然属于 shard1;
• 此时如果读 shard2,则会体现出 local 和 available 的区别:
  local:只取应该由 shard2 负责的数据(不包括 x);
  available:shard2 上有什么就读什么(包括 x);

mongoDB的事务

注意事项:
• 虽然看上去总是应该选择 local,但毕竟对结果集进行过滤会造成额外消耗。在一些无关紧要的场景(例如统计)下,也可以考虑 available;
• MongoDB <=3.6 不支持对从节点使用 {readConcern: "local"};
• 从主节点读取数据时默认 readConcern 是 local,从从节点读取数据时默认readConcern 是 available(向前兼容原因)。






 

官网mongoDB Java Client 事务使用示例:

final MongoClient client = MongoClients.create(uri);
/*
    Prereq: Create collections. CRUD operations in transactions must be on existing 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()
        .readPreference(ReadPreference.primary())
        .readConcern(ReadConcern.LOCAL)
        .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();
}

 db.fsyncLock() 与db.fsyncUnlock() 可以锁定/解锁节点的写入,可以测试

相关推荐