一、Springboot配置Redis
pom.xml文件需要的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!--<version>2.1.4.RELEASE</version>--> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>注意:1.是spring-boot-starter-data-reds;
因为Springboot2.0中redis客户端使用了Lettue,其依赖于commons,所以加入以上(似乎Jedis依然可以使用.)redis服务:下载redis的Windows版本,官网是Linux版本,Windows版由微软在github上维护,可前往下载,压缩包解压之后,点击redis-server.exe开启本地redis服务,端口号6379.可使用redisclient客户端查看数据库
二、application.properties配置
##是否启动日志SQL语句 spring.jpa.show-sql=true #Redis数据库索引(默认为0) spring.redis.database=0 spring.redis.host=localhost spring.redis.port=6379 #Redis服务器连接密码(默认为空) spring.redis.password= #springboot2.0redis默认客户端已换成lettuce #连接池最大连接数(使用负值表示没有限制)默认8 spring.redis.lettuce.pool.max-active=8 #连接池最大阻塞等待时间(使用负值表示没有限制)默认-1 spring.redis.lettuce.pool.max-wait=-1 #连接池中的最大空闲连接默认8 spring.redis.lettuce.pool.max-idle=8 #连接池中的最小空闲连接默认0 spring.redis.lettuce.pool.min-idle=0 spring.redis.timeout=5000三、自定义序列化(推荐使用StringRedisTemplate**)**
为redis客户端查看操作数据,redisTemplate需要进行序列化设置,默认配置的jdk序列化会导致在客户端查看不了数据(仍可使用内在函数存取修改,只是查看不了),为避免这种情况发生,使用StringRedisTemplate或自行配置序列化,自行配置可参考如下代码:
importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.data.redis.connection.RedisConnectionFactory; importorg.springframework.data.redis.core.RedisTemplate; importorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; importorg.springframework.data.redis.serializer.RedisSerializer; importorg.springframework.data.redis.serializer.StringRedisSerializer; @Configuration publicclassMyRedisConfig{ @Bean(name="redisTemplate") publicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory){ RedisTemplate<String,Object>redisTemplate=newRedisTemplate<>(); ////参照StringRedisTemplate内部实现指定序列化器 redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(keySerializer()); redisTemplate.setHashKeySerializer(keySerializer()); redisTemplate.setValueSerializer(valueSerializer()); redisTemplate.setHashValueSerializer(valueSerializer()); returnredisTemplate; } privateRedisSerializer<String>keySerializer(){ returnnewStringRedisSerializer(); } //使用Jackson序列化器 privateRedisSerializer<Object>valueSerializer(){ returnnewGenericJackson2JsonRedisSerializer(); } }简单测试代码(test)
@RunWith(SpringRunner.class) @SpringBootTest publicclassMyConfigRedisTemplateTest{ @Autowired privateRedisTemplateredisTemplate;//在MyRedisConfig文件中配置了redisTemplate的序列化之后,客户端也能正确显示键值对了 @Test publicvoidtest(){ redisTemplate.opsForValue().set("wujinxing","lige"); System.out.println(redisTemplate.opsForValue().get("wujinxing")); Map<String,Object>map=newHashMap<>(); for(inti=0;i<10;i++){ Useruser=newUser(); user.setId(i); user.setName(String.format("测试%d",i)); user.setAge(i+10); map.put(String.valueOf(i),user); } redisTemplate.opsForHash().putAll("测试",map); BoundHashOperationshashOps=redisTemplate.boundHashOps("测试"); Mapmap1=hashOps.entries(); System.out.println(map1); } staticclassUserimplementsSerializable{ privateintid; privateStringname; privatelongage; 省略getter,setter,toString... } }四、redis操作string,hash,set等
常见操作(均在controller上使用,仅做测试,实际项目应在service层使用redis):
@Controller @RequestMapping("/redis") publicclassRedisController{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(RedisController.class); @Autowired privateRedisTemplateredisTemplate=null; @Autowired privateStringRedisTemplatestringRedisTemplate=null; @RequestMapping("/stringAndHash") @ResponseBody publicMap<String,Object>testStringAndHash(){ redisTemplate.opsForValue().set("key1","value1"); //注意这里使用了JDK的序列化器,所以Redis保存时不是整数,不能运算 redisTemplate.opsForValue().set("int_key","1"); stringRedisTemplate.opsForValue().set("int","1"); //使用运算 stringRedisTemplate.opsForValue().increment("int",1); Map<String,Object>hash=newHashMap<>(); hash.put("field1","value1"); hash.put("field2","value2"); stringRedisTemplate.opsForHash().putAll("hash2",hash);//将Hashmap存储到redis中 stringRedisTemplate.opsForHash().put("hash2","field3","value3"); //绑定散列操作的key,这样可以连续对同一个散列数据类型进行操作 BoundHashOperationshashOps=stringRedisTemplate.boundHashOps("hash2"); hashOps.delete("field2","field1");//删除元素 hashOps.put("field4","value4");//添加元素 //LOGGER.info(hashOps.entries().toString()); Map<String,Object>map=newHashMap<>(); map.put("success",true); returnmap; } @RequestMapping("/list") @ResponseBody publicMap<String,Object>testList(){ //链表从左到右的顺序为v10,v8,v6,v4,v2 stringRedisTemplate.opsForList().leftPushAll("list1","v2","v4","v6","v8","v10"); //链表从左到右的顺序为v1,v3,v5,v7,v9 stringRedisTemplate.opsForList().rightPushAll("list2","v1","v3","v5","v7","v9"); //绑定list2操作链表 BoundListOperationslistOps=stringRedisTemplate.boundListOps("list2"); Objectresult1=listOps.rightPop();//从右边弹出一个成员 LOGGER.info("list2的最右边元素为:"+result1.toString()); Objectresult2=listOps.index(1);//获取定位元素,下标从0开始 LOGGER.info("list2下标为1的元素为"+result2.toString()); listOps.leftPush("v0");//从左边插入链表 Longsize=listOps.size();//求链表长 LOGGER.info("list2的长度为:"+size); Listelement=listOps.range(0,size-2);//求链表区间成员 LOGGER.info("list2从0到size-2的元素依次为:"+element.toString()); Map<String,Object>map=newHashMap<>(); map.put("success",true); returnmap; } @RequestMapping("/set") @ResponseBody publicMap<String,Object>testSet(){ //重复的元素不会被插入 stringRedisTemplate.opsForSet().add("set1","v1","v1","v3","v5","v7","v9"); stringRedisTemplate.opsForSet().add("set2","v2","v4","v6","v5","v10","v10"); //绑定sert1集合操作 BoundSetOperationssetOps=stringRedisTemplate.boundSetOps("set1"); setOps.add("v11","v13"); setOps.remove("v1","v3"); Setset=setOps.members();//返回所有元素 LOGGER.info("集合中所有元素:"+set.toString()); Longsize=setOps.size();//求成员数 LOGGER.info("集合长度:"+String.valueOf(size)); Setinner=setOps.intersect("set2");//求交集 setOps.intersectAndStore("set2","set1_set2");//求交集并用新的集合保存 LOGGER.info("集合的交集:"+inner.toString()); Setdiff=setOps.diff("set2");//求差集 setOps.diffAndStore("set2","set1-set2");//求差集并用新的集合保存 LOGGER.info("集合的差集:"+diff.toString()); Setunion=setOps.union("set2");//求并集 setOps.unionAndStore("set2","set1=set2");//求并集并用新的集合保存 LOGGER.info("集合的并集:"+union.toString()); Map<String,Object>map=newHashMap<>(); map.put("success",true); returnmap; } /** *redis操作有序集合 *@return */ @RequestMapping("/zset") @ResponseBody publicMap<String,Object>testZSet(){ Set<ZSetOperations.TypedTuple<String>>typedTupleSet=newHashSet<>(); for(inti=1;i<=9;i++){ //分数 doublescore=i*0.1; //创建一个TypedTuple对象,存入值和分数 ZSetOperations.TypedTupletypedTuple=newDefaultTypedTuple<String>("value"+i,score); typedTupleSet.add(typedTuple); } LOGGER.info("新建的set:"+typedTupleSet.toString()); //往有序集合插入元素 stringRedisTemplate.opsForZSet().add("zset1",typedTupleSet); //绑定zset1有序集合操作 BoundZSetOperations<String,String>zSetOps=stringRedisTemplate.boundZSetOps("zset1"); zSetOps.add("value10",0.26); Set<String>setRange=zSetOps.range(1,6); LOGGER.info("下标下1-6的set:"+setRange.toString()); //按分数排序获取有序集合 Set<String>setScore=zSetOps.rangeByScore(0.2,0.6); LOGGER.info("按分数排序获取有序集合:"+setScore.toString()); //定义值范围 RedisZSetCommands.Rangerange=newRedisZSetCommands.Range(); range.gt("value3");//大于value3 //range.gte("value3");//大于等于value3 //range.lt("value8");//小于value8 range.lte("value8");//小于等于value8 //按值排序,注意这个排序是按字符串排序 Set<String>setLex=zSetOps.rangeByLex(range); LOGGER.info("按值排序:"+setLex.toString()); zSetOps.remove("value9","value2");//删除元素 Doublescore=zSetOps.score("value8");//求分数 LOGGER.info("求value8的分数:"+score); //在下标区间按分数排序,同时返回value和score Set<ZSetOperations.TypedTuple<String>>rangeSet=zSetOps.rangeWithScores(1,6); LOGGER.info("在下标区间按分数排序,同时返回value和score:"+rangeSet.toString()); //在下标区间按分数排序,同时返回value和score Set<ZSetOperations.TypedTuple<String>>scoreSet=zSetOps.rangeByScoreWithScores(1,6); LOGGER.info("在下标区间按分数排序,同时返回value和score:"+scoreSet.toString()); //按从大到小排序 Set<String>reverseSet=zSetOps.reverseRange(2,8); LOGGER.info("按从大到小排序:"+reverseSet.toString()); Map<String,Object>map=newHashMap<>(); map.put("success",true); returnmap; } @RequestMapping("/multi") @ResponseBody publicMap<String,Object>testMulti(){ stringRedisTemplate.opsForValue().set("key1","value1"); /*Listlist=(List)stringRedisTemplate.execute((RedisOperationsoperations)->{ operations.watch("key1"); operations.multi(); operations.opsForValue().set("key2","value2"); //operations.opsForValue().increment("key1",1); //获取的值将为null,因为redis知识把命令放入队列 Objectvalue2=operations.opsForValue().get("key2"); System.out.println("命令在队列,所以value2为null["+value2+"]"); operations.opsForValue().set("key3","value3"); Objectvalue3=operations.opsForValue().get("key3"); System.out.println("命令在队列,所以value3为null["+value3+"]"); //执行exce()命令,将先判断key1是否在监控后被修改过,如果是则不执行事务,否则就执行事务 returnoperations.exec(); }); System.out.println(list);*/ Map<String,Object>map=newHashMap<>(); map.put("success",true); returnmap; } }五、Service层使用redis
service层上简单使用redis的例子:
@Service publicclassCityServiceImplimplementsCityService{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(CityServiceImpl.class); @Autowired privateCityMappercityMapper; @Autowired privateRedisTemplateredisTemplate; /** *获取城市逻辑: *如果缓存存在,从缓存中获取城市信息 *如果缓存不存在,从DB中获取城市信息,然后插入缓存 */ @Override publicCityfindCityById(Longid){ //从缓存中获取城市信息 Stringkey="city_"+id; ValueOperations<String,City>operations=redisTemplate.opsForValue(); //缓存存在 booleanhasKey=redisTemplate.hasKey(key); if(hasKey){ Citycity=operations.get(key); LOGGER.info("CityServiceImpl.findCityById():从缓存中获取了城市>>"+city.toString()); returncity; } //从DB中获取城市 Citycity=cityMapper.findById(id); //插入缓存 operations.set(key,city,10,TimeUnit.SECONDS);//缓存的时间仅有十秒钟 LOGGER.info("CityServiceImpl.findCityById():城市插入缓存>>"+city.toString()); LOGGER.info("刚才加入redis的数据是:"+operations.get(key)); returncity; } @Override publicLongsaveCity(Citycity){ returncityMapper.saveCity(city); } /** *更新城市逻辑: *如果缓存存在,删除 *如果缓存不存在,不操作 */ @Override publicLongupdateCity(Citycity){ Longret=cityMapper.updateCity(city); //缓存存在,删除缓存 Stringkey="city_"+city.getId(); booleanhasKey=redisTemplate.hasKey(key); if(hasKey){ redisTemplate.delete(key); LOGGER.info("CityServiceImpl.updateCity():从缓存中删除城市>>"+city.toString()); } returnret; } @Override publicLongdeleteCity(Longid){ Longret=cityMapper.deleteCity(id); Stringkey="city_"+id; booleanhasKey=redisTemplate.hasKey(key); if(hasKey){ redisTemplate.delete(key); LOGGER.info("CityServiceImpl.deleteCity():从缓存中删除城市ID>>"+id); } returnret; } }以上代码参考于<深入实践Springboot2.x>,网上的相关教程等.
本文内容总结:
原文链接:https://www.cnblogs.com/kingstar718/p/10941958.html