Я использую 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();
}
};
Так что теперь у меня есть следующие вопросы (ответы на любой из них оценены):
- Почему это работает с
RedisCallback
, но нес SessionCallback
? - Можно ли использовать эти транзакции с кластером redis, если все ключи в моих
doInRedis
соответственно execute
методах одинаковы? - Когда я выполняю это с
executePipelined
вместо execute
кажется, что все еще команды не приходят как одно массовое сообщение.Я установил точку останова после multi
и все еще могу видеть, что эта команда прибыла, когда просматривал redis с monitor
до того, как другие команды (incr
+ expire
) будут выполнены
Примечание: КакЯ использую Spring Boot 2.0.3 Я использую драйвер Lettuce Redis.Но переключение на джедаев приводит к тем же результатам.