MongoDB 支持的文档事务主要适用于副本集(replicasets)和分片集群(sharded clusters),并且这些事务是跨多个文档的。具体来说,MongoDB 提供了以下几种类型的文档事务:
多文档事务:这是 MongoDB 4.0 及更高版本中引入的最常见的文档事务类型。它允许你在单个事务中跨多个集合执行多个读写操作。这些操作要么全部成功,要么全部失败,从而保持数据的一致性。
单文档事务:虽然 MongoDB 通常与多文档事务一起讨论,但实际上单个文档的更新操作在 MongoDB 中也是原子性的。也就是说,单个文档的 update 或 replace 操作本身就是原子的,不需要显式的事务。但是,当需要跨多个文档或集合保持一致性时,就需要使用多文档事务。
读写事务:MongoDB 的事务支持读写操作。你可以在一个事务中读取数据,基于这些数据做出决策,然后写入或更新数据。
分布式事务:在分片集群中,MongoDB 支持跨多个分片的事务。这意味着你可以在一个事务中访问多个分片上的数据,并确保这些操作的原子性。
会话(Sessions):在 MongoDB 中,事务与会话相关联。每个事务都在一个会话的上下文中执行。会话提供了在客户端和 MongoDB 服务器之间跟踪事务状态的方法。
隔离性:MongoDB 的事务提供了隔离性保证,这意味着在事务执行期间,其他事务或操作不会看到该事务未提交的更改。
持久性:一旦事务提交,MongoDB 就会确保更改是持久的,即使系统发生故障也不会丢失。
在Java中,使用MongoDB的官方Java驱动程序(MongoDB Java Driver)来控制事务通常涉及以下步骤:
连接到MongoDB副本集或分片集群。
创建一个会话(ClientSession)。
在会话中开始事务。
执行多个读写操作。
提交或回滚事务。
关闭会话。
以下是一个简单的Java代码示例,演示了如何使用MongoDB Java Driver控制事务:
java
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import java.util.Arrays;
public class MongoTransactionExample {
public static void main(String[] args) {
// 连接到MongoDB(这里以副本集为例)
MongoCredential credential = MongoCredential.createCredential("username", "databaseName", "password".toCharArray());
MongoClientSettings settings = MongoClientSettings.builder()
.applyToClusterSettings(builder ->
builder.hosts(Arrays.asList(new ServerAddress("host1:27017"), new ServerAddress("host2:27017"))))
.credential(credential)
.build();
MongoClient mongoClient = MongoClients.create(settings);
try (MongoDatabase database = mongoClient.getDatabase("databaseName")) {
// 创建一个新的会话
try (ClientSession session = mongoClient.startSession()) {
// 设置会话级别为事务
session.startTransaction();
// 获取集合
MongoCollection<Document> collection = database.getCollection("collectionName");
// 执行一个写操作
UpdateResult updateResult = collection.updateOne(session, Filters.eq("someField", "someValue"),
new Document("$set", new Document("newField", "newValue")));
// ... 在这里可以添加其他读写操作 ...
// 如果所有操作都成功,提交事务
session.commitTransaction();
System.out.println("Transaction committed successfully");
} catch (Exception e) {
// 发生异常时,回滚事务
if (session != null) {
session.abortTransaction();
}
e.printStackTrace();
}
}
// 关闭客户端连接
mongoClient.close();
}
}
注意:
你需要将上述代码中的 "username", "databaseName", "password", "host1:27017", "host2:27017", "collectionName", "someField", "someValue", "newField", "newValue" 替换为你自己的实际值。
确保你的MongoDB集群是副本集或分片集群,因为单实例MongoDB不支持事务。
请注意错误处理和资源管理。在上面的示例中,我们使用了try-with-resources语句来自动关闭MongoDatabase和ClientSession。如果你不使用try-with-resources,则需要确保在不再需要它们时显式关闭它们。
在执行事务时,确保所有操作都在相同的会话中执行,以确保它们属于同一个事务。