在spring data redis reactive中,链接redis操作的正确方法是什么?

sqxo8psd  于 2021-06-09  发布在  Redis
关注(0)|答案(1)|浏览(707)

spring-data-redis-reactive ,写入操作返回redis执行结果,这使得链接操作非常困难。以redis in action第1章中的reddit为例。我尝试这样重新实现:

@Service
public class ArticleService {

    private final ReactiveStringRedisTemplate redisTemplate;

    private final long voteScore = 432L;

    public ArticleService(ReactiveStringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public Mono<Article> createArticle(Article article) {
        long now = System.currentTimeMillis();
        Map<String, String> newArticle = new HashMap<>();
        newArticle.put("title", article.getTitle());
        newArticle.put("link", article.getLink());
        newArticle.put("poster", article.getPoster());
        newArticle.put("time", String.valueOf(now));
        newArticle.put("votes", "1");
        return redisTemplate.opsForValue()
                            .increment("article:")
                            .doOnNext(id -> redisTemplate.opsForSet().add("voted:" + id.toString(), article.getPoster()).subscribe())
                            .doOnNext(id -> redisTemplate.expire("votes:" + id.toString(), Duration.ofDays(7)).subscribe())
                            .doOnNext(id -> redisTemplate.opsForHash().putAll("article:" + id.toString(), newArticle).subscribe())
                            .doOnNext(id -> redisTemplate.opsForZSet().add("score:", "article:" + id.toString(), now + voteScore).subscribe())
                            .doOnNext(id -> redisTemplate.opsForZSet().add("time:", "article:" + id.toString(), now).subscribe())
                            .map(id -> {
                                article.setId(id);
                                article.setVotes("1");
                                return article;
                            });
    }

}

如你所见,我用 doOnNext 以避免丢失 increment ,并且有一个 subscribe() 在每个 doOnNext 确保每一个redis操作都被执行。但我不认为这是推荐的方法。我认为应用程序应该尽量避免 subscribe() 主要集中在链接流上。
什么是正确的方法来做许多redis写操作 spring-data-redis-reactive ?

tez616oj

tez616oj1#

避免在两者之间订阅,如果您是从web界面调用流,spring将在最后订阅流。下面是一个如何实现的示例

return redisTemplate.opsForValue()
                            .increment("article:")
                            .flatMap(id -> // Mono.zip will execute concurrently all the modifications below
                              Mono.zip(redisTemplate.opsForSet().add("voted:" + id.toString(), article.getPoster()),
                                  redisTemplate.expire("votes:" + id.toString(), Duration.ofDays(7)),
                                  redisTemplate.opsForHash().putAll("article:" + id.toString(), newArticle),
                                  redisTemplate.opsForZSet().add("score:", "article:" + id.toString(), now + voteScore),
                                  redisTemplate.opsForZSet().add("time:", "article:" + id.toString(), now)
                              )
                                  .map(tuple -> id))
                            .map(id -> {
                                article.setId(id);
                                article.setVotes("1");
                                return article;
                            });

但您应该考虑将这些修改执行到 MULTI redis命令以确保以原子方式发生https://redis.io/commands/multi. 因为您没有任何验证和/或限制,所以不需要评估https://redis.io/commands/eval

相关问题