reactive 编程+redisson 如何分页的问题

bleulucaswu · 2024-10-11 05:13:09 · 147 次点击
- SpringBoot WebFlux 3.1.0 + redisson 3.27.1 + redis stack 7 单机
- webflux control 要求业务代码返回 mono
```java
    @Bean
    public RouterFunction<ServerResponse> route(CacheHandler cacheHandler) {
        return RouterFunctions.route()
                .GET("......", cacheHandler::xxxxxxx)
                .build();
```
- redissonReactiveClient 是 client
  - redissonReactiveClient.getSearch(codec).search(.....); 查询 redis 返回 mono<SearchResult>
  - 所以 cacheHandler::xxxxxxx 中 call 上面的查询
  - 如果做分页的话,SearchResult 里面有 total 和 List<Document>当前页数据
  
- 但是我如何在一个请求中查出所有数据呢,也就是 reactive 编程怎么搞个循环查询啊
  - 只能将第一次查询的 mono block()拿到 total 吗,但是貌似 reactive 编程不该是这个写法...
  - 如果 Mono<SearchResult> cc = client.search(..第一页数据).cache();
    - 然后 return cc.flatMap(c -> client.search(.. c.getTotal, 然后传参剩下所有数据)).concatWith(cc).collectList();
    - 测试之后返回空的,因为 client.search 本身也是异步多线程的,这个操作在另一个线程进行,webflux 就给我空数据了,还有就是第二个 search 也拿不到真正的 total

所以这个该咋做啊
    -
举报· 147 次点击
登录 注册 站外分享
9 条回复  
ZGame 初学 2024-10-11 08:33:28
请求所有数据可以通过 merge ,zip 等操作符吧, 另外可以看看 hs-web ,用的就是响应式。响应式更多时候有点像函数式编程,看看你的操作能不能通过函数式的方式,关注入参出参,还有函数转换方法,尽量减少副作用和外部的变量直接传入,so.. 其实你会发现用不好比用命令式的方式写代码更难受
OctVan 初学 2024-10-11 09:30:21
https://projectreactor.io/docs/core/release/reference/#sinks
可以用这个一直翻页,直到取完数据
spkingr 初学 2024-10-11 09:46:14
遇事不决问 AI ,这种问题问 AI 最好,他都能给你写好。
编程式风格确实不推荐使用 for 循环,用 for 也是配合 yield 。
你这个 flatMap 按理来说应该是可以的,我复制你的问题给 AI ,AI 就简单的给了一个参考代码,你可以看看,看能不能改改用上:

    public Mono<SearchResult> searchWithPagination(int pageNumber, int pageSize) {
        return redissonReactiveClient.getSearch(StringCodec.INSTANCE)
            .search(SearchArgs(pageNumber, pageSize)) // 返回是 Mono<SearchResult>,有条数和页数吧
            .flatMap(initialSearchResult -> { // flatMap 抽取结果
                int totalPages = initialSearchResult.getTotal() / pageSize; // 修改一下,获取页数
                if (pageNumber < totalPages) {
                                        // 这里继续查询并合并
                    return redissonReactiveClient.getSearch(StringCodec.INSTANCE)
                        .search(SearchArgs(pageNumber, pageSize))
                        // map 则是转换结果
                        .map(nextSearchResult -> combineSearchResults(initialSearchResult, nextSearchResult));
                } else {
                    // 没有数据
                    return Mono.just(initialSearchResult);
                }
            });
    }

    private SearchResult combineSearchResults(SearchResult initialResult, SearchResult nextResult) {
        List<Document> combinedDocuments = new ArrayList<>(initialResult.getDocuments());
        combinedDocuments.addAll(nextResult.getDocuments());
        SearchResult combinedResult = new SearchResult();
        combinedResult.setTotal(initialResult.getTotal());
        combinedResult.setDocuments(combinedDocuments);
        return combinedResult;
    }
yazinnnn0 小成 2024-10-11 10:31:53
这个效果?
https://i.imgur.com/md49XXc.png

用的 mutiny, 跟 reactor 差不多
拿到 total 的 mono 时做 flatmap 转换, 然后把你的循环查询转换称序列+步进(都用 fp 了就别用传统 for 循环了...
然后把序列做 fold 操作, java 里貌似需要用 reduce 去实现, fold 的初始值设置为 mono 形式的零值, 比如 Mono.just(List.empty())之类, fold 的 operation 去合并 acc 和新查出来的值(mutiny 用 combine, reactor 里应该有类似的 api)
返回顶部