【发布时间】:2021-12-18 20:49:06
【问题描述】:
我有这个服务方式:
@Transactional
override suspend fun deleteByCarId(carId: Long) {
routeRepository.deleteByCarId(carId)
routePlanRepository.deleteByCarId(carId)
carRepository.deleteById(carId)
}
路线计划(中)和汽车(最后一行)被删除,但routeRepository上的删除没有被执行。
interface RouteRepository : CoroutineCrudRepository<Route, Long> {
fun deleteByCarId(carId: Long)
// ...
}
interface RoutePlanRepository : CoroutineCrudRepository<RoutePlan, Long> {
suspend fun deleteByCarId(carId: Long)
// ...
}
所以,我发现这可能是因为RouteRepository 在删除方法上错过了suspend,但有人可以解释一下,为什么这很重要?
编辑 1
通过进一步考虑更一般的情况,我认为创建Flow 的非暂停存储库函数似乎不一定标记为suspend。但我不明白为什么。所有其他方法似乎都需要suspend - 但为什么呢?通常我可以从协程运行一个非挂起函数并执行它(当然我们不应该,因为它可能会阻塞线程 - 对吧?)。
我的假设是创建Flow 不需要是可暂停的,因为创建它的操作很快,并且只有它的订阅最终会执行查询。
在上面的示例中,没有订阅Flow,因为该方法返回Unit - 这就是不执行删除的原因?
但是,我仍然不明白,为什么用suspend 标记存储库方法会改变行为。现在查询的创建本身就是一个异步操作,因此它(删除查询的创建)成为整个请求处理链的一部分?
但我希望在挂起函数中创建查询不会自动订阅?谁能解释一下?
编辑 2
我创建这个问题是因为我认为应该更好地记录什么是可能的,什么不是:https://github.com/spring-projects/spring-data-commons/issues/2503
文档目前声明delete 需要suspend,但未明确提及:
对于返回值,从 Reactive 到 Coroutines API 的转换如下:
fun handler(): Mono<Void>变为suspend fun handler()
fun handler(): Mono<T>变为suspend fun handler(): T或suspend fun handler(): T?取决于 Mono 是否可以为空(具有更多静态类型的优势)
fun handler(): Flux<T>变为fun handler(): Flow<T>
https://docs.spring.io/spring-data/r2dbc/docs/current/reference/html/#kotlin.coroutines.reactive
【问题讨论】:
-
您的意思是所有这些
deleteByCarId()函数实际上都返回流吗?因为从您的示例中它们返回Unit,而不是流。 -
在示例中他们返回
Unit,我不明白为什么执行暂停但没有暂停?通过进一步思考,我发现理解它对流也有帮助。我也不明白带有Unitreturn 的挂起函数在 r2dbc 中的行为。它是否在引擎盖下创建了一个流程(不返回它)?
标签: kotlin spring-webflux kotlin-coroutines project-reactor spring-data-r2dbc