Spring Boot Redis Transaction с Multi Exec не работает с истечением - PullRequest
0 голосов
/ 05 октября 2018

Я использую Spring Boot 2.0.3 с Redis (через stringRedisTemplate).Я написал простой ограничитель скорости, чтобы ограничить доступ пользователей к определенным ресурсам.Я хочу отправлять incr и expire для повторного атомарного анализа, чтобы быть уверенным, что ни один ключ не будет создан без 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

Похоже, что expire вызывает ошибку здесь.

Я теперь попробовал это немного по-другому - с 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. Можно ли использовать эти транзакции с кластером redis, если все ключи в моих doInRedis соответственно execute методах одинаковы?
  3. Когда я выполняю это с executePipelined вместо execute кажется, что все еще команды не приходят как одно массовое сообщение.Я установил точку останова после multi и все еще могу видеть, что эта команда прибыла, когда просматривал redis с monitor до того, как другие команды (incr + expire) будут выполнены

Примечание: КакЯ использую Spring Boot 2.0.3 Я использую драйвер Lettuce Redis.Но переключение на джедаев приводит к тем же результатам.

...