带有Multi Exec的Spring Boot Redis事务无法使用到期

时间:2018-10-05 15:08:04

标签: java spring spring-boot redis spring-data-redis

我正在使用带有Redis的Spring Boot 2.0.3(通过stringRedisTemplate)。我写了一个简单的速率限制器来限制用户对某些资源的访问。我想自动发送一个incr和一个expire来使redis失效,这样我可以确定没有expire不会创建任何键。我不想在全局范围内启用Redis事务,而只是在这种情况下。为此,我编写了以下内容:

SessionCallback<List<Object>> sessionCallback = new SessionCallback<List<Object>>() {
    @SuppressWarnings("unchecked")
    @Override
    public <K, V> List<Object> execute(RedisOperations<K, V> operations) throws DataAccessException {
        operations.multi();

        operations.opsForValue().increment((K) key, 1);
        operations.expire((K) key, rateIntervalTime.getTimeAmount(), rateIntervalTime.getTimeUnit());

        return operations.exec();
    }
};

执行此操作会引发以下错误:org.springframework.data.redis.RedisSystemException: Unknown redis exception; nested exception is java.lang.IllegalArgumentException: Incorrect number of transaction results. Expected: 2 Actual: 1

看起来过期在这里触发了错误。

我现在尝试了一些不同的操作-用RedisCallback而不是SessionCallback。这行得通!

RedisCallback<List<Object>> redisCallback = new RedisCallback<List<Object>>() {
    @Override
    public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
        connection.multi();

        connection.incr(key.getBytes());
        connection.expire(key.getBytes(),
                    rateIntervalTime.getTimeUnit().toSeconds(rateIntervalTime.getTimeAmount()));

        return connection.exec();
    }
};

所以现在我有以下问题(对他们中的任何一个的回答都很感激):

  1. 为什么它可以与RedisCallback一起使用而不与SessionCallback一起使用?
  2. 如果我的doInRedisexecute方法中的所有键都相同,是否可以将这些事务与Redis群集一起使用?
  3. 当我用executePipelined而不是execute执行此命令时,似乎仍然没有命令作为一条批量消息到达。我在multi之后设置了一个断点,并且在执行其他命令(monitor + incr之前,用expire观看redis时仍然可以看到该命令到达

注意:当我使用Spring Boot 2.0.3时,我正在使用Lettuce Redis驱动程序。但是切换到Jedis会得到相同的结果。

0 个答案:

没有答案