For one, before
The company has a core project redis client is always using Jedis, the technical director of the later request to replace the Jedis client with a more efficient and efficient lettuce client, and use the spring framework’s own RedisTemplate class to operate Redis.
However, things are hard to predict, is such a simple demand but let the old master turned over the boat…
Two, accident rehearsal
By default, this development task should be very easy:
- Shift the jedis connection pool configuration item in the configuration file to replace it with lettuce.
- Remove the jedis configuration code from the project;
- Replace the redisTemplate where you use jedis.
Pseudo code
Other configuration items are displayed one by one
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 = 2000Copy to clipboardErrorCopied
Copy the code
replace
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 = 200Copy to clipboardErrorCopied
Copy the code
The business code is also changed from Jedis to the pseudo-code of redisTemplate Jedis:
/** * Set the inventory to redis-jedis *@paramGoodId commodity ID *@paramCount Inventory *@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";
}
Copy the code
Pseudocode for redisTemplate:
/** * Set the inventory of goods to redis-redistemplate *@paramGoodId commodity ID *@paramCount Inventory *@return* /
@PatchMapping("/storage")
public String setStorage(
@RequestParam("goodId") String goodId,
@RequestParam("count") String count) {
redisTemplate.opsForValue().set("good:" + goodId, count);
return "success";
}
Copy the code
However, after all the work was done and the launch was full of confidence, a large number of online bugs broke out. It is a serious production accident.
From the error log, we can see clearly that the data of String type cannot be converted to int, so I have a big question mark in my mind: it is clear that the String I saved in Redis can be converted to numeric type.
Cause analysis,
View the data using the Redis-Desktop-Manager visual tool
The string key-value pair value is overloaded with double quotation marks
What! You don’t have jedis, you have redisTemplate?
After some code review, it appears that there is a missing step in the process of using redisTemplate: Configuration serialization is usually added in the configuration center or configuration file if there is no special configuration or redis connection pool is used
Host = 172.0.0.1 spring.redis.port = 6379 spring.redis.password = 123456Copy to clipboardErrorCopiedCopy the code
Then inject the redisTemplate and you’re ready to use it, very simple.
However, the default serializer used by RedisTemplate is the JDK’s built-in serializer.
Look at the class diagram of the RedisTemplate
Since RedisTemplate inherits RedisAccessor, which implements InitializingBean, afterPropertiesSet() can be overridden after the RedisTemplate class is initialized, Set up the serializer.
The solution
Write a redis configuration class to reset the serializer.
@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;
}
Copy the code
The StringRedisSerializer serializer is configured only for the String type of Redis. You can configure the Hash object type based on project requirements.
Spring comes with a variety of serializers, as follows
You can also customize serializers by implementing the RedisSerializer interface and rewriting the serialize() and deserialize() methods.
For demonstration purposes, instead of writing the global redis configuration class, reset the serializer directly in the interface, with the following pseudocode:
@PatchMapping("/storage")
public String setStorage(
@RequestParam("goodId") String goodId,
@RequestParam("count") String count) {
redisTemplate.setKeySerializer(new StringRedisSerializer()); // Reset the serializer for redis String key
redisTemplate.setValueSerializer(new StringRedisSerializer()); // Reset the serializer for redis String value
redisTemplate.opsForValue().set("good:" + goodId, count);
return "success";
}
Copy the code