You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:58:40