Jedis和redisTemplate 共用问题--序列化不一致(生产事故->解决->两个redisTemplate)
Jedis和redisTemplate 共用问题
老项目用Jedis,放入redis中,用的是比较老的框架,还进行序列化.
用redisTemplate试了下拿不到.因为序列化的方式不同
Jedis
老项目的Put方法.
@Override public boolean put(String key, Object value, int TTL) throws Exception { Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.set(SerializeUtil.serialize(key), SerializeUtil.serialize(value)); jedis.expire(SerializeUtil.serialize(key), TTL); } catch (Exception e) { log.error("缓存存入失败", e); return false; } finally { returnResource(jedisPool, jedis); } return true; }
然后把工具类搬过来了
public class SerializeUtil { /** *序列化 * * @param object * @return */ public static byte[] serialize(Object object) { ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(object); byte[] bytes = baos.toByteArray(); return bytes; } catch (Exception e) { } return null; } /** * 反序列化 * * @param bytes * @return */ public static Object unserialize(byte[] bytes) { ByteArrayInputStream bais = null; try { bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } catch (Exception e) { } return null; } }
写个测试来看看
@Test public void test1() { Jedis jedis = null; jedis = new Jedis("localhost", 6379); jedis.set(SerializeUtil.serialize("xx"), SerializeUtil.serialize("brgfewfe")); jedis.expire(SerializeUtil.serialize("xx"), 3000); }
redisTemplate尝试和解决
配置什么就不说了,想着这样应该能解决吧,发现不行.后来查了好多资料,发现redisTemplate的序列化需要配置方法
@Autowired private static RedisTemplate redisTemplate; ValueOperations valueOperations = redisTemplate.opsForValue(); Object wenzhouToken = valueOperations.get(SerializeUtil.serialize("xx")); System.out.println(wenzhouToken);
于是
RedisSerializerUtil redisSerializerUtil = new RedisSerializerUtil(); redisTemplate.setKeySerializer(redisSerializerUtil); redisTemplate.setHashKeySerializer(redisSerializerUtil); redisTemplate.setValueSerializer(redisSerializerUtil); redisTemplate.setHashValueSerializer(redisSerializerUtil); ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set("xx",token,3000, TimeUnit.SECONDS);
附上序列化工具类
public class RedisSerializerUtil implements RedisSerializer<Object> { private final Charset charset; public RedisSerializerUtil() { this(Charset.forName("UTF8")); } public RedisSerializerUtil(Charset charset) { Assert.notNull(charset, "Charset must not be null!"); this.charset = charset; } @Override public byte[] serialize(Object object) throws SerializationException { return object == null ? null : SerializeUtil.serialize(object); } @Override public Object deserialize(byte[] bytes) throws SerializationException { return bytes == null ? null : SerializeUtil.unserialize(bytes); } }
这样就和上面的jedis序列化一样了,就可以取了
一点,用完后记得还原默认的序列化方式
RedisSerializerUtil redisSerializerUtil = new RedisSerializerUtil(); redisTemplate.setKeySerializer(redisSerializerUtil); redisTemplate.setHashKeySerializer(redisSerializerUtil); redisTemplate.setValueSerializer(redisSerializerUtil); redisTemplate.setHashValueSerializer(redisSerializerUtil); ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set("xx",token,3000, TimeUnit.SECONDS); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(stringRedisSerializer);
问题!!!
线上发布后,发现和RedisConfig
@Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(redisConnectionFactory); // Json序列化配置 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // String 的序列化 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; }
两边序列化不一样,然后线上用的定时刷新字典炸了!!!抢救了1个多小时。我的天
注意序列化一定要一致
第二版代码类似,只是把序列化一致了,线上没出现问题。但是不能心存侥幸,因为有可能在设置序列化后还没来得及换回原来的方式,这个时间节点,可能会执行刷新字典的方法,这个时候还是会出现问题!!!
后来经过高人指点,配置两个redisTemplate也就隔离开,最终代码
@Configuration @EnableCaching //开启注解 public class RedisConfig extends CachingConfigurerSupport { //编写redisTemplate @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(redisConnectionFactory); // Json序列化配置 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // String 的序列化 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean(name = "SerializeRedisTemplate") public RedisTemplate<String, Object> getRedisTemplate1(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(redisConnectionFactory); // Json序列化配置 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); RedisSerializerUtil redisSerializerUtil = new RedisSerializerUtil(); template.setKeySerializer(redisSerializerUtil); template.setHashKeySerializer(redisSerializerUtil); template.setValueSerializer(redisSerializerUtil); template.setHashValueSerializer(redisSerializerUtil); return template; } }
这样就隔离开来了
1 @Resource(name = "SerializeRedisTemplate") 2 private RedisTemplate serializeRedisTemplate; 3 4 5 redisTemplate.opsForValue().set("xx", token, 60 * 40, TimeUnit.SECONDS); 6 serializeRedisTemplate.opsForValue().set("xx", token, 60 * 40, TimeUnit.SECONDS);
网上找的比较全的配置
1 package com.example.config; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 6 import org.springframework.boot.context.properties.ConfigurationProperties; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Configuration; 9 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 import org.springframework.data.redis.core.RedisTemplate; 11 import org.springframework.data.redis.core.StringRedisTemplate; 12 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 14 import com.fasterxml.jackson.annotation.JsonAutoDetect; 15 import com.fasterxml.jackson.annotation.PropertyAccessor; 16 import com.fasterxml.jackson.databind.ObjectMapper; 17 18 import redis.clients.jedis.JedisPoolConfig; 19 20 @Configuration 21 @EnableAutoConfiguration 22 public class RedisConfig { 23 24 private static Logger logger = LoggerFactory.getLogger(RedisConfig.class); 25 26 @Bean 27 @ConfigurationProperties(prefix="spring.redis") 28 public JedisPoolConfig getRedisConfig(){ 29 JedisPoolConfig config = new JedisPoolConfig(); 30 return config; 31 } 32 33 @Bean 34 @ConfigurationProperties(prefix="spring.redis") 35 public JedisConnectionFactory getConnectionFactory(){ 36 JedisConnectionFactory factory = new JedisConnectionFactory(); 37 JedisPoolConfig config = getRedisConfig(); 38 factory.setPoolConfig(config); 39 logger.info("JedisConnectionFactory bean init success."); 40 return factory; 41 } 42 43 @Bean 44 public RedisTemplate<?, ?> getRedisTemplate(){ 45 RedisTemplate<?,?> template = new StringRedisTemplate(getConnectionFactory()); //只能对字符串的键值操作 46 System.out.println("生成<?,?>template:" + template); 47 return template; 48 } 49 50 @Bean(name = "LongRedisTemplate") 51 public RedisTemplate<String, Long> getRedisTemplate1(){ 52 RedisTemplate<String,Long> template = new RedisTemplate<String,Long>(); //只能对字符串的键值操作 53 template.setConnectionFactory(getConnectionFactory()); 54 55 // 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化) 56 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); 57 ObjectMapper om = new ObjectMapper(); 58 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 59 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 60 jackson2JsonRedisSerializer.setObjectMapper(om); 61 62 template.setKeySerializer(jackson2JsonRedisSerializer); 63 template.setValueSerializer(jackson2JsonRedisSerializer); 64 template.setHashKeySerializer(jackson2JsonRedisSerializer); 65 template.setHashValueSerializer(jackson2JsonRedisSerializer); 66 template.afterPropertiesSet(); 67 68 System.out.println("生成<String, Long>template:" + template); 69 return template; 70 } 71 72 @Bean(name = "StringRedisTemplate") 73 public RedisTemplate<String, String> getRedisTemplate2(){ 74 RedisTemplate<String,String> template = new RedisTemplate<String,String>(); //只能对字符串的键值操作 75 template.setConnectionFactory(getConnectionFactory()); 76 77 // 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化) 78 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); 79 ObjectMapper om = new ObjectMapper(); 80 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 81 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 82 jackson2JsonRedisSerializer.setObjectMapper(om); 83 84 template.setKeySerializer(jackson2JsonRedisSerializer); 85 template.setValueSerializer(jackson2JsonRedisSerializer); 86 template.setHashKeySerializer(jackson2JsonRedisSerializer); 87 template.setHashValueSerializer(jackson2JsonRedisSerializer); 88 template.afterPropertiesSet(); 89 90 System.out.println("生成<String, String>template:" + template); 91 return template; 92 } 93 94 @Bean(name = "IntegerRedisTemplate") 95 public RedisTemplate<String, Integer> getRedisTemplate3(){ 96 RedisTemplate<String,Integer> template = new RedisTemplate<String,Integer>(); //只能对字符串的键值操作 97 template.setConnectionFactory(getConnectionFactory()); 98 99 // 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化) 100 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); 101 ObjectMapper om = new ObjectMapper(); 102 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 103 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 104 jackson2JsonRedisSerializer.setObjectMapper(om); 105 106 template.setKeySerializer(jackson2JsonRedisSerializer); 107 template.setValueSerializer(jackson2JsonRedisSerializer); 108 template.setHashKeySerializer(jackson2JsonRedisSerializer); 109 template.setHashValueSerializer(jackson2JsonRedisSerializer); 110 template.afterPropertiesSet(); 111 112 System.out.println("生成<String,Integer>template:" + template); 113 return template; 114 } 115 }
import java.util.Set; import javax.annotation.Resource; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SetOperations; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class RedisController { @Resource(name = "StringRedisTemplate") private RedisTemplate<String, String> stringRedisTemplate; @Resource(name = "LongRedisTemplate") private RedisTemplate<String, Long> longRedisTemplate; @Resource(name = "IntegerRedisTemplate") private RedisTemplate<String, Integer> integerRedisTemplate; @RequestMapping(value = "/redis") public String testRedis() { System.out.println("stringRedisTemplate:" + stringRedisTemplate); System.out.println("longRedisTemplate:" + longRedisTemplate); System.out.println("integerRedisTemplate:" + integerRedisTemplate); testStringRedis(); testLongRedis(); testIntegerRedis(); return "成功!"; } private void testStringRedis() { SetOperations<String, String> set = stringRedisTemplate.opsForSet(); //保存Set set.add("set1","22"); set.add("set1","33"); set.add("set1","33"); Set<String> resultSet =stringRedisTemplate.opsForSet().members("set1"); //获取Set System.out.println("resultSet:"+resultSet); } private void testLongRedis() { SetOperations<String, Long> set = longRedisTemplate.opsForSet(); set.add("set2",22L); set.add("set2",22L); set.add("set2",23L); Set<Long> resultSet =longRedisTemplate.opsForSet().members("set2"); System.out.println("resultSet:"+resultSet); } private void testIntegerRedis() { SetOperations<String, Integer> set = integerRedisTemplate.opsForSet(); set.add("set3",222); set.add("set3",333); set.add("set3",555); Set<Integer> resultSet =integerRedisTemplate.opsForSet().members("set3"); System.out.println("resultSet:"+resultSet); } }
学习时的痛苦是暂时的 未学到的痛苦是终生的