Spring Boot MongoDB交易:写入冲突错误

von4xj4u  于 2022-12-23  发布在  Spring
关注(0)|答案(1)|浏览(257)

环境

  • 蒙古数据库:(Atlas 4+)
  • 驱动程序:4.2.3
  • 我们使用的是Sping Boot 数据MongoDB(2.5.4)

我们使用的MongoDB事务使用回调API。同样的情况也发生在Core API上。

样品

private ThreadLocal<MongoOperations> sessionMongoTemplate;

    try (final ClientSession session = getClientSession()) {
       this.sessionMongoTemplate = ThreadLocal.withInitial(() -> getMongoOperations().withSession(session));

       session.withTransaction(() -> {
           // do some work
           // call a method which does (sessionMongoTemplate.get().insert(entity);) 
           // (this throws WriteConflict Error)
       });
   }

错误

  • com.mongodb.蒙戈命令异常:命令失败,出现错误112(WriteConflict):'写入冲突错误:此操作与另一个操作冲突。请重试您的操作或多文档事务。“(位于服务器abc.mongodb.net:1234上)。完整响应为{“errorLabels”:[“ transient 事务错误”],“确定”:0,“错误消息”:“写入冲突错误:此操作与另一操作冲突,请重试您的操作或多单据业务。",“code”:112,“代码名称”:“写入冲突”*
    查询:

我们已经将MongoOperations/Template与ClientSession相关联。该会话打开了一个事务。但是,当代码使用SessionScoped MongoOperations时,它会失败,就像它不知道打开的事务一样。
我们能不能不要用这种方法?
按照中的示例:事务体中的https://docs.mongodb.com/v4.2/core/transactions-in-applications/,我们使用MongoClient,它工作正常。我们可以不使用会话作用域的MongoTemplate吗?

fafcakar

fafcakar1#

所以,经过一番调查,我认为事情是这样的...
对于数据库操作(命令,如insert或update),如果不在ACID事务中,冲突操作(示例中的第二个会话)将阻止当前操作的提交并重试。请记住,在ACID事务之外,MongoDB具有文档级原子性。
但是,对于多文档事务,行为是不同的。如果遇到writeConflict,它会立即失败。这种策略是这样设计的,允许您的应用程序检测到这种情况,然后等待X毫秒并重试N次,其中X和N是您的舒适度。
您正在设置的参数与第二个会话将阻塞和等待的时间无关,但它与系统在建立锁之前允许等待的时间有关。默认值为5 ms。您的示例显示为3秒(3000 ms)。假设您指的是会话号2上的锁-您允许它花多长时间来获取锁。问题在于writeConflict是在任何获取锁的尝试之前检测到的,因为在ACID事务中,应该由应用程序而不是驱动程序来执行等待。

相关问题