Spring Data MongoDB 教程

MongoDB 会话

从 3.6 版开始,MongoDB 支持会话(Session)的概念。会话的使用实现了 MongoDB 的因果一致性模型,它保证了以因果关系的顺序来运行操作。这些会话被分成 ServerSession 实例和 ClientSession 实例。在本文中,当我们谈到会话时,我们指的是 ClientSession。

警告:客户端会话内的操作与会话外的操作不隔离。

MongoOperations 和 ReactiveMongoOperations 都提供了将 ClientSession 绑定到操作的网关方法。MongoCollection 和 MongoDatabase 使用会话代理对象来实现 MongoDB 的集合和数据库接口,因此您不需要在每个调用上添加会话。这意味着对 MongoCollection#find() 的调用被委托给 MongoCollection#find(ClientSession)。

注意:诸如(Reactive)MongoOperations#getCollection 之类的方法返回本机 MongoDB Java 驱动网关对象(例如:MongoCollection),这些对象本身为 ClientSession 提供了专用方法,这些方法不是会话代理的。在直接与 MongoCollection 或 MongoDatabase 交互时,您应该在需要时提供 ClientSession,而不是通过 MongoOperations 上的#execute 回调之一。

同步 ClientSession 支持

以下示例显示了会话的用法:

ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
   .causallyConsistent(true)
   .build();

// 从服务器获取一个新的会话
ClientSession session = client.startSession(sessionOptions);

template.withSession(() -> session)
   .execute(action -> {
       Query query = query(where("name").is("Durzo Blint"));
       // 像以前一样使用 MongoOperation方法,ClientSession 会被自动应用
       Person durzo = action.findOne(query, Person.class);

       Person azoth = new Person("Kylar Stern");
       azoth.setMaster(durzo);

       action.insert(azoth);

       return azoth;
   });

// 关闭会话
session.close();

注意,在处理 DBRef 实例(尤其是延迟加载的实例)时,在加载所有数据之前不要关闭客户端会话,这一点至关重要。否则,延迟提取将失败。

响应式 ClientSession 支持

响应式使用与命令式相同的构建块,如下例所示:

ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
   .causallyConsistent(true)
   .build();

// 获取一个 Publisher,用于新的会话检索
Publisher<ClientSession> session = client.startSession(sessionOptions);

template.withSession(session)
   .execute(action -> {
       Query query = query(where("name").is("Durzo Blint"));
       return action.findOne(query, Person.class)
           .flatMap(durzo -> {
               Person azoth = new Person("Kylar Stern");
               azoth.setMaster(durzo);
               // 像以前一样使用 ReactiveMongoOperation 方法,自动获得并应用 ClientSession
               return action.insert(azoth);
           });
   }, ClientSession::close) // 请确保关闭 ClientSession
   .subscribe(); // 在你订阅之前什么都不会发生

通过使用一个提供实际会话的 Publisher,你可以将会话的获取推迟到实际订阅的时候。但是,你仍然需要在完成后关闭会话,这样就不会用无效的会话污染服务器。当你不再需要会话时,使用 execution 上的 doFinally 钩子来调用 ClientSession#close() 方法关闭会话。如果你喜欢对会话本身有更多的控制,你可以通过驱动获得 ClientSession 对象,并通过供应商来提供它。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号