Spring Boot响应式REST服务:实现存在则抛异常不存在则保存
响应式Spring Boot + Cassandra:实现“不存在则保存,存在则抛异常”逻辑
作为响应式编程新手,这种“先检查再操作”的逻辑确实容易让人绕晕,我来帮你把现有代码的两部分逻辑串联起来,完全贴合响应式的思维方式~
核心思路
响应式编程里不能用传统“同步查完再判断”的阻塞思路,而是要通过Mono的操作符把整个流程串成一个异步流。我们需要先执行“检查条目是否存在”的操作,然后根据结果分支:
- 如果条目已存在:返回一个包含异常的Mono(响应式里必须用
Mono.error()抛出异常,不能直接throw) - 如果条目不存在:执行你原来的转换和保存逻辑
写法一:基于existsById的分支处理
这是最贴合你现有代码的写法,直接把existsById的结果作为分支判断依据:
@Override public Mono<String> createItem(ItemCreateParam itemCreateParam) { String itemName = itemCreateParam.getName(); // 先执行存在性检查,再根据结果分支 return reactiveItemRepository.existsById(itemName) .flatMap(itemExists -> { if (itemExists) { // 存在则抛出自定义异常(建议替换成你自己的业务异常类) return Mono.error(new IllegalStateException("Item with name '" + itemName + "' already exists")); } else { // 不存在则执行转换、保存逻辑 return Mono.just(itemCreateParam) .flatMap(this::convert) .log() .flatMap(reactiveTemplateRepository::save) .map(savedItem -> savedItem.getName()); } }); }
写法二:基于findById的流分支(更符合响应式思维)
另一种更“响应式”的写法是直接用findById:如果找到条目就抛异常,没找到就执行保存逻辑,用switchIfEmpty处理空结果的情况:
@Override public Mono<String> createItem(ItemCreateParam itemCreateParam) { String itemName = itemCreateParam.getName(); return reactiveItemRepository.findById(itemName) // 如果找到已有条目,直接抛异常 .flatMap(existingItem -> Mono.error(new IllegalStateException("Item '" + existingItem.getName() + "' already exists"))) // 如果没找到(流为空),执行保存逻辑 .switchIfEmpty( Mono.just(itemCreateParam) .flatMap(this::convert) .log() .flatMap(reactiveTemplateRepository::save) .map(savedItem -> savedItem.getName()) ); }
关键注意点
- 异常处理:一定要用
Mono.error()抛出异常,不能直接在lambda里throw——直接throw会破坏响应式流的异步特性,导致异常无法被上层的onError处理。 - 竞态条件:高并发场景下,可能出现多个请求同时通过存在性检查的情况,所以一定要确保Cassandra里
name是主键(或有唯一性约束),数据库层面的约束是最后一道防线。 - 自定义异常:建议创建专门的业务异常类(比如
ItemAlreadyExistsException),替换示例中的IllegalStateException,这样上层的异常处理会更清晰。
内容的提问来源于stack exchange,提问作者Viraj
相关产品推荐
相关产品推荐

