Spring Data R2DBC嵌套属性持久化:Mono与Flux组合方案
解决Spring Data R2DBC中关联实体的顺序持久化问题
看起来你踩中了反应式编程里的经典坑——冷流的订阅触发问题。你定义了soonTeBeSavedItems这个Flux,但根本没触发它的订阅执行,所以saveItems里的itemRepository.saveAll完全没跑起来。加上外键约束要求先存Order再存Item,我们得把这两个操作严格串联起来,确保顺序和执行触发。
第一步:补全Item的外键关联
你的Item类目前没有关联Order的字段,这是外键约束的前提,先给Item添加关联Order的ID字段:
class Item( id: UUID, var someData: String, var orderId: UUID // 新增:对应数据库的外键列,关联Order的id ) : Persistable<UUID> { @Id private var id: UUID = id override fun getId(): UUID? { return id } override fun isNew(): Boolean { return true } }
第二步:修改saveOrder方法,串联Order和Item的保存
核心思路是:保存Order拿到生成的ID → 给所有Item设置Order ID → 保存Items → 等Items保存完成后返回Order。这样既保证了外键要求的顺序,又触发了Items的保存操作:
private fun saveOrder(order: Order): Mono<Order> { return orderRepository.save(order) .flatMap { savedOrder -> // 给当前Order下的所有Item设置关联的Order ID order.items.forEach { it.orderId = savedOrder.id } // 保存所有Item,等全部完成后返回保存好的Order itemRepository.saveAll(order.items) .then(Mono.just(savedOrder)) } }
为什么这样能解决问题?
- 反应式流是冷流:只有当流被订阅时,内部的操作才会执行。原来的代码里
soonTeBeSavedItems只是定义了,但没有被任何订阅者触发,所以saveItems完全没执行。 flatMap会自动订阅内部流:这里flatMap里的itemRepository.saveAll返回的Flux会被flatMap自动订阅,确保Items的保存操作被执行。then(Mono.just(savedOrder)):会等Items的Flux全部完成(即所有Item都保存成功)后,才返回保存好的Order,完美符合外键约束的顺序要求。
额外优化:用Mono.when显式等待操作完成
如果你想更清晰地表达“等Items保存完再返回Order”,也可以用Mono.when实现:
private fun saveOrder(order: Order): Mono<Order> { return orderRepository.save(order) .flatMap { savedOrder -> val itemsWithOrderId = order.items.map { it.apply { orderId = savedOrder.id } } // 将Flux<Item>转成Mono<Void>,表示等待所有Item保存完成 val saveItemsDone = itemRepository.saveAll(itemsWithOrderId).then() // 等saveItemsDone完成后,返回savedOrder Mono.when(saveItemsDone).thenReturn(savedOrder) } }
最后验证saveOrders方法
你的saveOrders方法可以保持不变:
fun saveOrders(orders: List<Order>): Flux<Order> { return Flux.fromIterable(orders).flatMap { saveOrder(it) } }
Flux.fromIterable(orders).flatMap { saveOrder(it) }会逐个处理每个Order,每个Order的保存流程都是先存Order再存Items,最终返回的Flux
内容的提问来源于stack exchange,提问作者Markus Ratzer
相关产品推荐
相关产品推荐

