mongodb - 为什么在 Spring 响应式 Mongo 中订阅有效而阻止无效?

标签 mongodb spring-boot spring-data-mongodb project-reactor spring-webflux

我从 Spring Initializr 创建了一个新项目通过选择 KotlinGradleM7Web-reactive

我做了一个小项目:

data class Person (val id: String)

@Component class PersonHandler(val template: ReactiveMongoTemplate) 
{
    init
    {
        println("Initializing")

        val jim: Mono<Person> =  template.save(Person("Jim"))
        val john: Mono<Person> = template.save(Person("John"))
        val jack: Mono<Person> = template.save(Person("Jack"))

        launch(jim)
        launch(john)
        launch(jack)

        println("Finished Initializing")
    }

    fun launch(mono: Mono<Person>)
    {
        mono.subscribe({println(it.id)}, {println("Error")}) // This works
        // mono.block()  This just hangs
    } 
}

我尝试将三个人保存到数据库中。 save 方法只返回一个需要执行的 Mono。如果我尝试通过简单的订阅来执行它,一切都很好:

Initializing
Finished Initializing
2017-12-21 13:14:39.513  INFO 17278 --- [      Thread-13] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:158}] to localhost:27017
2017-12-21 13:14:39.515  INFO 17278 --- [      Thread-12] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:4, serverValue:159}] to localhost:27017
2017-12-21 13:14:39.520  INFO 17278 --- [      Thread-14] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:5, serverValue:160}] to localhost:27017
Jim
Jack
John

但是,当我使用 block 而不是 subscribe 应用程序挂起:

Initializing
2017-12-21 13:16:47.200  INFO 17463 --- [      Thread-14] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:163}] to localhost:27017

如果我手动查询数据库,我看到 Jim 已保存,但 Jack 和 John 未保存。

这是一个错误,还是我做错了什么?我想保证用户在代码进一步运行之前就在数据库中,所以我真的很想使用 block.

我不确定它是否相关,但我收到编译器警告

Accessing nonfinal property template in constructor

有一个最小的工作示例。它包含两个分支。一种是解决该问题的方法。

https://github.com/martin-drozdik/spring-mongo-bug-example

最佳答案

我认为这可能是 Spring Framework 错误/可用性问题。

首先,让我强调一下 subscribeblock 之间的区别:

  • subscribe 方法启动工作并立即返回。因此,当应用程序的其他部分运行时,您无法保证操作已完成。
  • block 是一个阻塞操作:它触发操作并等待其完成。

对于初始化工作,组合操作和调用 block 一次可能是最好的选择:

val jim: Mono<Person> =  template.save(Person("Jim"))
val john: Mono<Person> = template.save(Person("John"))
val jack: Mono<Person> = template.save(Person("Jack"))
jim.then(john).then(jack).block();

正如您所说,使用 block 会挂起应用程序。我怀疑这可能是一个 Spring 上下文初始化问题 - 如果我没记错的话,这个过程可能会在某些部分假设一个线程,并使用一个响应式(Reactive)管道来安排许多线程上的工作。

您能否创建一个最小的示例应用程序(仅使用 Java/Spring Boot/Spring Data Reactive Mongo)并在 https://jira.spring.io 上报告?

关于mongodb - 为什么在 Spring 响应式 Mongo 中订阅有效而阻止无效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47924911/

相关文章:

node.js - 使用 typescript 创建 Mongoose 模型 - 子文档

java - CascadeType.PERSIST 无法正确保存

java - Liquibase 上必须指定changeLogFile 错误

mongodb - 如何在 MongoDB 中存储 blob 数据?

java - 将 Spring Mongo 更新转换为 JSON 字符串

python - Linux Nagios 检查问题 : MongoDB check_mongodb. py

node.js - 每个模型对象的动态表规范

javascript - MongoDB无法使用部分来遍历元素

sql - 如何按国家/地区查询 PostGIS 中的数据?

spring - 使用 Spring Data MongoDB Criteria 构建动态查询