在MongoDB中,对单个文档的操作是原子的。因为您可以使用嵌入式文档和数组来捕获单个文档结构中的数据之间的关系,而不是在多个文档和集合之间进行规范化,所以这种单文档原子性消除了许多实际用例中对多文档事务的需求。
对于需要原子性地读写多个文档(在单个或多个集合中)的情况,MongoDB支持多文档事务。使用分布式事务,可以跨多个操作,集合,数据库,文档和分片使用事务。
事务代码演示
/*
For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl";
For a sharded cluster, connect to the mongos instances; e.g.
String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin";
*/
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();
}
- 在4.2版中,MongoDB引入了分布式事务,它增加了对分片群集上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。
要在MongoDB 4.2部署(副本集和分片群集)上使用事务,客户端必须使用针对MongoDB 4.2更新的MongoDB驱动程序。
多文档交易是原子性的(即提供“全有或全无”主张):
提交事务时,将保存在事务中进行的所有数据更改,并在事务外部可见。也就是说,一个事务在回滚其他事务时将不会提交其某些更改。
在提交事务之前,在事务外部看不到在事务中进行的数据更改。
但是,当一个事务写入多个分片时,并非所有外部读取操作都需要等待已提交事务的结果在所有分片上可见。例如,如果提交了一个事务,并且在分片A上可以看到写1,但是在分片B上仍然看不到写2,则外部读处于读关注状态"local"
可以读取写1的结果而看不到写2。当事务中止时,在事务中进行的所有数据更改都将被丢弃,而不会变得可见。例如,如果事务中的任何操作失败,则事务中止,并且在事务中进行的所有数据更改都将被丢弃,而不会变得可见。