Spring Webflux查询后删除功能失效问题排查与解决
问题原因及解决办法
核心原因
- 响应式操作未纳入主数据流:Service中用
doOnNext调用删除方法,但userRepository.deleteUserById(userId)返回的Mono是独立的响应式流,既没整合到主序列里,也没被订阅——响应式操作只有被订阅或加入主数据流才会实际执行,所以删除逻辑根本没触发。 - 自定义删除Query存在缺陷:PostgreSQL的
DELETE语句默认不会返回被删除的记录,你定义的@Query("DELETE FROM tb_user WHERE userid = $1")返回Mono<User>,实际执行后不会返回数据,即便删除操作被触发,也无法正确返回预期结果(这不是本次删除失效的主要原因)。
解决步骤
1. 修正Repository的删除方法
根据需求调整Query:
- 如果需要返回被删除的用户数据,添加
RETURNING *子句:
@EnableR2dbcRepositories public interface UserRepository extends ReactiveCrudRepository<User, Long> { @Query("SELECT * FROM tb_user WHERE username LIKE $1") Mono<User> findByUsername(String username); // 添加RETURNING * 获取被删除的用户记录 @Query("DELETE FROM tb_user WHERE userid = $1 RETURNING *") Mono<User> deleteUserById(Long userId); }
- 如果不需要返回用户数据,直接返回
Mono<Void>:
@Query("DELETE FROM tb_user WHERE userid = $1") Mono<Void> deleteUserById(Long userId);
2. 重写Service的删除逻辑
用flatMap替代map+doOnNext,把删除操作整合到主响应式数据流中:
@Override public Mono<ResponseEntity<String>> deleteUserById(Long userId) { return userRepository.findById(userId) // flatMap处理返回Mono的异步操作,将删除逻辑纳入主数据流 .flatMap(user -> { UserDto deletedUser = UserMapper.USER_MAPPER_INSTANCE.toUserDto(user); String successMsg = "User: " + deletedUser.getUsername() + " deleted!"; // 执行删除后返回成功消息 return userRepository.deleteUserById(userId) .thenReturn(successMsg); }) .map(ResponseEntity::ok) .defaultIfEmpty(ResponseEntity .status(HttpStatus.NOT_FOUND) .body("UserId: " + userId + " Not found")); }
原理说明
flatMap会将删除操作的Mono与主数据流串联,当Spring订阅Controller返回的Mono时,会依次执行查询用户→删除用户→返回结果的完整逻辑,确保所有响应式操作都被触发执行。而原代码中的doOnNext仅作为副作用触发,不会等待或纳入后续操作,导致删除逻辑被忽略。
内容的提问来源于stack exchange,提问作者AM0007
相关产品推荐
相关产品推荐

