«Это третий день моего участия в ноябрьском испытании обновлений. Подробную информацию об этом событии см.:Вызов последнего обновления 2021 г.". PS: Сколько дней написано, N напишет несколько. Обязательно пишите правильный экземпляр, иначе статья не будет засчитана.
1. Предыстория
Клиент основного проекта компании Redis всегда использовал jedis.Ответственное техническое лицо позже попросило заменить клиент jedis более эффективным клиентом lettuce и использовать класс RedisTemplate, поставляемый с инфраструктурой Spring, для работы с Redis.
Однако все непредсказуемо, и именно такое простое требование заставляет старого водителя перевернуться. . .
2. Репетиция аварии
Согласно предварительно заданным результатам, эта задача разработки должна быть очень простой:
- Замените элемент конфигурации пула соединений jedis в файле конфигурации на салат;
- Удалите код, связанный с конфигурацией jedis в проекте;
- Замените использование Jedis с перераспределением.
Поддельный код
Другие элементы конфигурации не отображаются по одному
spring.redis.jedis.pool.max-idle = 200
spring.redis.jedis.pool.min-idle = 10
spring.redis.jedis.pool.max-active = 200
spring.redis.jedis.pool.max-wait = 2000
заменить
spring.redis.lettuce.pool.max-idle = 200
spring.redis.lettuce.pool.min-idle = 10
spring.redis.lettuce.pool.max-wait = 2000
spring.redis.lettuce.pool.max-active = 200
Бизнес-код также изменен с jedis на redisTemplate.
Псевдокод для джедаев:
/**
* 设置商品库存到redis - jedis
* @param goodId 商品id
* @param count 库存量
* @return
*/
@PatchMapping("/storage/jedis")
public String setStorageByJedis(
@RequestParam("goodId") String goodId,
@RequestParam("count") String count) {
Jedis jedis = getJedis();
jedis.set("good:" + goodId, count);
jedis.close();
return "success";
}
Псевдокод redisTemplate:
/**
* 设置商品库存到redis - redisTemplate
* @param goodId 商品id
* @param count 库存量
* @return
*/
@PatchMapping("/storage")
public String setStorage(
@RequestParam("goodId") String goodId,
@RequestParam("count") String count) {
redisTemplate.opsForValue().set("good:" + goodId, count);
return "success";
}
Однако после того, как вся работа была проделана и онлайн-релиз с полной уверенностью, онлайн-баги разразились в больших масштабах.Это серьезная производственная авария.
Из журнала ошибок мы ясно видим, что, поскольку данные типа String не могут быть преобразованы в тип int, в моем сердце стоит большой вопросительный знак: очевидно, то, что я сохраняю в redis, — это строка, которую можно преобразовать в числовой тип. ?
Анализ причин
Просмотр данных с помощью инструмента визуализации Redis-Desktop-Manager
Обнаружено, что существует множество пар ключ-значение строкового типа.пара двойных кавычек
Нани! Как использовать jedis, если у вас его нет, и заменить его на redisTemplate?
После некоторой проверки кода я обнаружил, что в процессе использования redisTemplate стало на один шаг меньше:Настроить сериализациюКак правило, если нет специальной конфигурации или вы хотите использовать пул соединений Redis, он используется только в центре конфигурации или в файле конфигурации.
spring.redis.host = 172.0.0.1
spring.redis.port = 6379
spring.redis.password = 123456Copy to clipboardErrorCopied
Затем введите redisTemplate, и вы можете использовать его, очень просто.
Однако сериализатор по умолчанию, используемый RedisTemplate, — это сериализатор, поставляемый с JDK, см. исходный код:
Посмотрите на диаграмму классов Redistemplate
После перераспределения наследует Redisaccessor, Redisaccessor реализует понизанияBean, поэтому после инициализации класса Redistemplate его можно переписатьafterPropertiesSet()
метод, который устанавливает сериализатор.
решение
Напишите класс конфигурации Redis и сбросьте сериализатор.
@Configuration
@ConditionalOnClass(RedisOperations.class)
public class RedisTemplateAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name="redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate template=new RedisTemplate();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
Здесь настроен только сериализатор StringRedisSerializer для строкового типа Redis, можно добавить конфигурацию типа объекта Hash в соответствии с реальными потребностями проекта.
Spring поставляется с различными сериализаторами, а именно:
Вы также можете настроить сериализатор, вам нужно реализовать интерфейс RedisSerializer и переопределить методы serialize() и deserialize().
Для удобства демонстрации глобальный класс конфигурации Redis не пишется, а сериализатор сбрасывается прямо в интерфейсе, псевдокод выглядит следующим образом:
@PatchMapping("/storage")
public String setStorage(
@RequestParam("goodId") String goodId,
@RequestParam("count") String count) {
redisTemplate.setKeySerializer(new StringRedisSerializer()); // 重置redis string类型key的序列化器
redisTemplate.setValueSerializer(new StringRedisSerializer()); // 重置redis string类型value的序列化器
redisTemplate.opsForValue().set("good:" + goodId, count);
return "success";
}