Spring整合MongoDB(七)----会话和事务

本文介绍了如何在SpringData中使用MongoDB的ClientSession支持,包括会话概念、因果一致性、事务管理(TransactionTemplate和MongoTransactionManager)以及事务内部的特殊行为,如连接设置、集合操作和计数限制。
摘要由CSDN通过智能技术生成


从3.6版本开始,MongoDB支持会话的概念。会话的使用启用了MongoDB的 因果一致性(Causal Consistency)模型,该模型保证操作以尊重其因果关系的顺序运行。这些实例分为ServerSession实例和ClientSession实例。在本节中,当我们谈到session时,我们指的是ClientSession。
客户端会话内的操作不会与会话外的操作隔离。
MongoOperations和ReactiveMongoOperations都提供了将ClientSession绑定到操作的网关方法。MongoCollection和MongoDatabase使用实现了MongoDB的集合和数据库接口的会话代理对象,因此你不需要在每个调用上添加会话。这意味着对MongoCollection#find()的潜在调用被委托给MongoCollection#find(ClientSession)。
(Reactive)MongoOperations#getCollection等方法返回native MongoDB Java Driver网关对象(如MongoCollection),这些对象本身为ClientSession提供了专用方法。这些方法不是会话代理的。当直接与MongoCollection或MongoDatabase交互时,应该在需要的地方提供ClientSession,而不是通过对MongoOperations的#execute回调之一提供。

一、ClientSession支持

下面的例子展示了会话的用法:

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

ClientSession session = client.startSession(sessionOptions); --------1

template.withSession(() -> session)
    .execute(action -> {

        Query query = query(where("name").is("Durzo Blint"));
        Person durzo = action.findOne(query, Person.class);  --------2

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

        action.insert(azoth);                                --------3

        return azoth;
    });

session.close()                                              --------4

1. 从服务器获取新的会话。
2. 像以前一样使用MongoOperation方法。自动应用ClientSession3. 确保关闭ClientSession4. 关闭会话。

在处理DBRef实例时,尤其是延迟加载的实例,在加载所有数据之前不要关闭ClientSession是很重要的。否则,lazy fetch失败。

二、MongoDB事务

从版本4开始,MongoDB支持事务。事务建立在会话(Sessions)之上,因此需要一个active ClientSession。
除非在应用程序上下文中指定MongoTransactionManager,否则事务支持是关闭的。你可以使用setSessionSynchronization(ALWAYS)来参与正在进行的non-native MongoDB事务。
为了获得对事务的完全编程式控制,你可能需要在MongoOperations上使用会话回调。
以下示例显示了编程式事务控制:
编程式事务

ClientSession session = client.startSession(options);   --------1                

template.withSession(session)
    .execute(action -> {

        session.startTransaction();                     --------2                

        try {

            Step step = // ...;
            action.insert(step);

            process(step);

            action.update(Step.class).apply(Update.set("state", // ...

            session.commitTransaction();                --------3                

        } catch (RuntimeException e) {
            session.abortTransaction();                 --------4                
        }
    }, ClientSession::close)                            --------5                

1. 获取新的ClientSession2. 启动事务。
3. 如果一切如预期,提交更改。
4. 如果出问题了,把所有东西都倒回去。
5. 完成后不要忘记关闭会话。

前面的示例使你能够完全控制事务行为,同时在回调中使用会话范围的MongoOperations实例,以确保会话传递到每个服务器调用。为了避免这种方法带来的一些开销,可以使用TransactionTemplate来消除手动事务流的一些噪音。

三、使用TransactionTemplate / TransactionalOperator的事务

Spring Data MongoDB事务同时支持TransactionTemplate和TransactionalOperator。
使用TransactionTemplate/TransactionalOperator的事务

template.setSessionSynchronization(ALWAYS);                                 --------1    

// ...

TransactionTemplate txTemplate = new TransactionTemplate(anyTxManager);     --------2    

txTemplate.execute(new TransactionCallbackWithoutResult() {

    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) { --------3    

        Step step = // ...;
        template.insert(step);

        process(step);

        template.update(Step.class).apply(Update.set("state", // ...
    };
});

1.Template API配置期间启用事务同步。
2. 使用提供的PlatformTransactionManager创建TransactionTemplate3. 在回调中,已经注册了ClientSession和事务。

在运行时更改MongoTemplate的状态(你可能会认为在前面列表的第1项中是可能的)可能会导致线程和可见性问题。

四、使用MongoTransactionManager/ReactiveMongoTransactionManager的事务

MongoTransactionManager/ReactiveMongoTransactionManager是通往众所周知的Spring事务支持的网关。它允许应用程序使用Spring的托管事务功能。MongoTransactionManager将ClientSession绑定到线程,而ReactiveMongoTransactionManager则使用ReactorContext。MongoTemplate检测会话并相应地对与事务相关联的这些资源进行操作。MongoTemplate还可以参与其他正在进行的事务。以下示例显示如何使用MongoTransactionManager创建和使用事务:
使用MongoTransactionManager/ReactiveMongoTransactionManager的事务

@Configuration
static class Config extends AbstractMongoClientConfiguration {

    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) { --------1 
        return new MongoTransactionManager(dbFactory);
    }

    // ...
}

@Component
public class StateService {

    @Transactional
    void someBusinessFunction(Step step) {                                       --------2 

        template.insert(step);

        process(step);

        template.update(Step.class).apply(Update.set("state", // ...
    };
});

1. 在应用程序上下文中注册MongoTransactionManager2. 将方法标记为事务性方法。

@Transactional(readOnly = true)通知MongoTransactionManager也启动一个将ClientSession添加到传出请求的事务。

五、事务内部的特殊行为

在事务内部,MongoDB服务器的行为略有不同。

5.1 连接设置

MongoDB drivers 提供了一个专用的副本集(replica set)名称配置选项,使driver进入自动检测模式。此选项有助于在事务期间识别主复制集节点和命令路由。
请确保将replicaSet添加到MongoDB URI中。有关更多详细信息,请参阅连接字符串选项

5.2 集合操作

MongoDB不支持事务中的集合操作,例如创建集合。这也会影响首次使用时的动态集合创建。因此,确保所有必需的结构都已就位。

5.3 暂态错误

MongoDB可以为事务操作过程中出现的错误添加特殊标签。这些可能表示暂时性故障,这些故障可能仅通过重试操作而消失。出于这些目的,我们强烈建议使用Spring Retry。然而,可以覆盖MongoTransactionManager#doCommit(MongoTransactionObject) ,以实现MongoDB参考手册中概述的重试提交操作行为。

5.4 计数count

MongoDB count是根据收集统计数据进行操作的,这些统计数据可能无法反映事务中的实际情况。当在多document事务内部发出count命令时,服务器以错误50851进行响应。一旦MongoTemplate检测到active事务,所有公开的count()方法都会使用$match和$count运算符转换并委托给聚合框架,从而保留查询设置,如collation。
在聚合count帮助程序内部使用地理命令时会应用限制。以下运算符不能使用,必须用其他运算符替换:

  • $where→ $expr
  • $near→ $geoWithin with $center
  • $nearSphere→ $geoWithin with $centerSphere

使用Criteria.near(…)和Criteria.nearSphere(…)的查询必须重写为Criteria.within(…)各自的Criteria.withinSphere(…)。这同样适用于存储库查询方法中的near query关键字,该方法必须更改为within。另请参阅MongoDB JIRA ticket DRIVERS-518以获取更多参考。
以下代码段显示了会话绑定闭包中的count使用情况:

session.startTransaction();

template.withSession(session)
    .execute(action -> {
        action.count(query(where("state").is("active")), Step.class)
        ...

上面的代码片段由下面的命令中实现:

db.collection.aggregate(
   [
      { $match: { state: "active" } },
      { $count: "totalEntityCount" }
   ]
)

而不是:

db.collection.find( { state: "active" } ).count()
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值