# redis-study **Repository Path**: zhituaishangc/redis-study ## Basic Information - **Project Name**: redis-study - **Description**: redis学习记录 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-04-18 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # redis学习1 ## 一、概念复习 关系型数据库和非关系型数据库的区别 关系型数据库:数据之间有关联关系,数据存储在硬盘上,以表的形式存储数据。 非关系型数据库:redis,数据之间没有关联关系,以键值对的形式存储,存储在内存中。 与数据库交互比较耗时,查询一些不经常发生变化的数据时可以把其缓存在redis中,加快访问速度。 redis支持存储的值数据类型: 字符串,list,map,set,有序set redis持久化方式: RDB方式,在一定的间隔时间中检测key的变化,然后持久化数据。 jedis客户端操作redis ## 二、用jedis操作redis ```java public class Test1 { public static void main(String[] args) { //获取连接 //Jedis jedis=new Jedis("localhost",6379); Jedis jedis = getJedisClien();//使用jedis连接池来获取jedis //设置字符串值 jedis.set("username","zhangsan"); //带过期时间设置值 jedis.setex("password",10,"123"); //获取字符串 System.out.println(jedis.get("username")); //存储hash jedis.hset("student","name","zhangsan"); jedis.hset("student","age","18"); //获取map中的某个值 System.out.println(jedis.hget("student","age")); //获取整个map Map map = jedis.hgetAll("student"); Set> entries = map.entrySet(); for (Map.Entry entry : entries) { System.out.println(entry.getKey()+":"+entry.getValue()); } //存储列表 // jedis.lpush("list","a"); // jedis.lpush("list","b"); // jedis.rpush("list","c"); //list范围获取 List list = jedis.lrange("list", 0, -1); System.out.println(list); //list弹出 String ele = jedis.lpop("list"); System.out.println(ele); String ele2 = jedis.rpop("list"); System.out.println(ele2); //set集合类型数据 jedis.sadd("myset","java","php","c_sharp"); jedis.srem("myset","java");//移除set集合中的某个元素 Set myset = jedis.smembers("myset");//获取set集合的全部元素 System.out.println(myset); //有序set存储,根据给定的分数排序,分数越大越靠后 jedis.zadd("mysortSet",1,"a"); jedis.zadd("mysortSet",10,"c"); jedis.zadd("mysortSet",100,"b"); System.out.println(jedis.zrange("mysortSet",0,-1)); //指定某个key的过期时间 jedis.expire("student",15); jedis.close();//使用连接池获取到的连接,调用close方法就是把连接归还连接池 } /** * 用jedis连接池来获取jedis对象 * @return */ public static Jedis getJedisClien(){ JedisPoolConfig config=new JedisPoolConfig(); config.setMaxTotal(10); config.setMaxIdle(10); JedisPool pool=new JedisPool(config,"localhost",6379); return pool.getResource(); } } ``` ## 三、springboot整合redis spring提供了一个RedisTemplate对象可以用来操作redis,在springboot中当然也可以使用redisTemplate ### 3.1 整合步骤 引入redis的起步依赖 ```xml org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-test ``` 在配置文件中对redis和jedis的连接信息进行配置 ```yml spring: redis: host: localhost port: 6379 jedis: pool: max-idle: 10 max-active: 8 max-wait: -1 min-idle: 0 ``` 在需要操作redis的地方注入redisTemplate的对象,就可以使用 ```java @RunWith(SpringRunner.class) @SpringBootTest(classes = RedisStudyApplication.class) public class Test1 { @Autowired private RedisTemplate redisTemplate;//这个对象的泛型是 @Test public void test1(){ //存储和获取字符串 redisTemplate.boundValueOps("username").set("zhangsan"); //使用泛型是的模板对象,get方法返回的是Object Object value = redisTemplate.boundValueOps("username").get(); System.out.println(value); //存储和获取map redisTemplate.boundHashOps("demoMap").put("key1","value1"); Object value2 = redisTemplate.boundHashOps("demoMap").get("key1"); System.out.println(value2); } } ``` ### 3.2 自动注入的redistemplate对象详解 springboot提供了redis的自动配置类来创建redisTemplate对象,配置类如下: ```java @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } } ``` 可以看到其中提供了两个redisTemplate对象,一个泛型是RedisTemplate,另一个的泛型是。 使用这种方式注入的是泛型是的redisTemplate对象 ```java @Autowired private RedisTemplate redisTemplate; ``` 所以使用这个redisTemplate操作redis存储的key和value都是object类型的。 ### 3.3 使用StringRedisTemplate ```java /** * 测试 StringRedisTemplate来操作redis,序列化器使用的是 StringRedisSerializer */ @Test public void test2(){ //1.存储和获取字符串 stringRedisTemplate.boundValueOps("accountName").set("lyy"); //使用指定泛型的模板对象来操作redis,get方法返回的对象就是指定的泛型类型的 String value = stringRedisTemplate.boundValueOps("accountName").get(); System.out.println(value); //2.redis中存取hash类型的数据 stringRedisTemplate.boundHashOps("stringMap").put("key1","value1"); //通过redistemplate来获取hash类型的数据 Object value2 = stringRedisTemplate.boundHashOps("stringMap").get("key1"); System.out.println(value2); } ``` ### 3.4序列化器 将一个对象存储到redis中,需要把一个对象序列化即保存这个对象的状态,再把序列化的结果保存到redis中。 同样的,从redis中把一个对象读取到内存中需要反序列化这个对象。 spring提供了几个序列化器 ```text Jackson2JsonRedisSerializer JdkSerializationRedisSerializer OxmSerializer StringRedisSerializer GenericToStringRedisSerializer GenericJackson2JsonRedisSerializer ``` 当我们自动注入泛型是的redisTemplate对象时,默认使用的是jdk自己的序列化器,所以序列化后存储到redis的结果会和实际的内容有出入,不管是key还是value都多了一些特殊内容。 ![](https://gitee.com/zhituaishangc/image-sources/raw/master/redis/%E9%BB%98%E8%AE%A4%E5%BA%8F%E5%88%97%E5%8C%96%E5%99%A8%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96%E7%BB%93%E6%9E%9C.png) 当使用StringRedisTemplate时,序列化使用的是StringRedisSerializer这个序列化器,部分源码如下 ```java public class StringRedisTemplate extends RedisTemplate { /** * Constructs a new StringRedisTemplate instance. {@link #setConnectionFactory(RedisConnectionFactory)} * and {@link #afterPropertiesSet()} still need to be called. */ public StringRedisTemplate() { RedisSerializer stringSerializer = new StringRedisSerializer(); setKeySerializer(stringSerializer); setValueSerializer(stringSerializer); setHashKeySerializer(stringSerializer); setHashValueSerializer(stringSerializer); } ``` 使用这个序列化器把字符串序列化后再存储到redis中,序列化的结果和实际的内容是一样的 ![](https://gitee.com/zhituaishangc/image-sources/raw/master/redis/string%E5%BA%8F%E5%88%97%E5%8C%96%E5%99%A8%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96%E7%BB%93%E6%9E%9C.png) ### 3.5 自定义redisTemplate的泛型和序列化器 springboot自定配置的redisTemplate不满足使用要求时,可以自己在配置类中配置一个redisTemplate对象。 ```java /** * 自定义的redisTemplate对象 * @param redisConnectionFactory * @return */ @Bean public RedisTemplate objectRedisTemplate( RedisConnectionFactory redisConnectionFactory) { RedisTemplate template = new RedisTemplate<>(); //设置template的序列化器 template.setKeySerializer(new StringRedisSerializer());//设置key的序列化器 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class); //配置序列化器的属性 ObjectMapper mapper=new ObjectMapper(); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //配置这个属性后从redis中再拿取到的就还是原来的对象,不配置这个属性存进去的是对象,获取到的会是一个map serializer.setObjectMapper(mapper); template.setValueSerializer(serializer);//设置value的序列化器 template.setHashKeySerializer(serializer); template.setHashValueSerializer(serializer); template.setConnectionFactory(redisConnectionFactory); return template; } ``` 使用自定义的redisTemplate ```java /** * 使用自定义的redisTemplate,key的序列化器使用StringRedisSerializer,value的序列化器使用Jackson2JsonRedisSerializer */ @Test public void test3(){ //1.存储和获取字符串 myRedisTemplate.boundValueOps("demo3").set("demo3-value"); Object demo3Value = myRedisTemplate.boundValueOps("demo3").get(); System.out.println(demo3Value); //2.将一个map对象序列化成字符串然后存入redis中 redis中存储key-string类型 Map map=new HashMap<>(); map.put("key1","value1"); map.put("key2","value2"); myRedisTemplate.boundValueOps("mapString").set(map); Object map1 = myRedisTemplate.boundValueOps("mapString").get(); System.out.println(map1); //2.把一个自定义对象序列化成字符串存入redis reids中存储 key-string类型 Student stu=new Student("1","zhangsan",18); myRedisTemplate.boundValueOps("student").set(stu); Object student = myRedisTemplate.boundValueOps("student").get(); System.out.println(student); //3.给redis中存入hash类型的数据,hash中存储的是student对象(序列化成字符串),redis中存储的是key-hash类型 Student st1=new Student("2","st1",19); Student st2=new Student("3","st2",19); myRedisTemplate.boundHashOps("studentMap").put("st1",st1); myRedisTemplate.boundHashOps("studentMap").put("st2",st2); Object obj = myRedisTemplate.boundHashOps("studentMap").get("st1"); System.out.println(obj); } ``` 注意: 在配置value的序列化器时使用了 ```java //配置序列化器的属性 ObjectMapper mapper=new ObjectMapper(); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //配置这个属性后从redis中再拿取到的就还是原来的对象,不配置这个属性存进去的是对象,获取到的会是一个map serializer.setObjectMapper(mapper); ``` 是因为配置了这个后对象序列化成字符并存储到redis时字符串中会包含它的来源对象的信息,这样反序列时就可以重新反序列化成原来的对象。 此序列化器序列化对象的字符串的信息如下: ```java "[\"com.lyy.entity.Student\",{\"id\":\"1\",\"userName\":\"zhangsan\",\"age\":18}]" ``` 这个字符串中包含了原始类Student的全类名,所以反序列化时就可以根据这个把其还原成原来的对象。 ## 四、总结 redis中可以存储五种数据类型:String,List,hash,set,sortSet springboot操作redis使用的核心对象是redisTemplate springboot的redis自动配置类配置了两个redisTemplate,和StringRedisTemplate 存储一个对象到redis中需要把对象序列化,spring提供了多个序列化器。 可以自己配置指定泛型的redisTemplate,并指定序列化器。