JOOQ 3.17.2配置R2DBC时调用executeAsync触发阻塞方法异常
问题根因
你触发异常的核心原因是误用了JDBC场景下的executeAsync()API:
executeAsync()本质是把阻塞的execute()逻辑放到异步线程池执行,并没有走R2DBC的响应式流订阅逻辑,jOOQ的R2DBC适配层会直接拦截所有阻塞式执行调用,无论你是否将其放到异步线程中。- 当使用R2DBC连接工厂配置时,jOOQ的增删改查语句本身就实现了Reactive Streams的
Publisher接口,需要通过订阅的方式触发执行,不能调用传统JDBC生态下的execute()、executeAsync()、fetch()等阻塞方法。
修复方案
你已经引入了jooq-kotlin-coroutines和kotlinx-coroutines-reactor依赖,直接使用响应式查询的协程扩展即可,去掉executeAsync()调用:
// 直接使用初始化好的dsl实例即可,不需要重复DSL.using()包装 dsl.insertInto(table) .set(fromDomain(item)) .apply(builder) .await()
其他可选写法
如果你需要手动适配响应式流,可以通过Reactor包装查询后执行:
import reactor.core.publisher.Mono import kotlinx.coroutines.reactor.awaitSingle Mono.from( dsl.insertInto(table) .set(fromDomain(item)) .apply(builder) ).awaitSingle()
注意事项
- 不要重复通过
DSL.using(dsl.configuration())创建新的DSL实例,直接复用你初始化好的dsl实例即可,避免不必要的配置拷贝。 - 所有基于R2DBC的jOOQ查询,都要通过订阅
Publisher的方式触发,禁止调用任何阻塞执行相关的方法,否则都会触发你遇到的异常。 - jOOQ的Kotlin协程扩展已经为所有响应式查询预置了
await()等挂起方法,不需要自己额外包装异步逻辑。
内容的提问来源于stack exchange,提问作者Grantas Gadliauskas
相关产品推荐
相关产品推荐

