SpringBoot整合Redis案例分析
SpringBoot整合Redis案例分析
这篇文章主要介绍了SpringBoot整合Redis案例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot整合Redis案例分析文章都会有所收获,下面我们一起来看看吧。
Springboot整合Redis
如果没有Redis,就先去下载
下载路径cmd,然后
redis-server.exe redis.windows.conf
命令既可以启动服启动服务后,后面的才可以进行整合
在redis目录下点击redis-cli.exe进行测试结果查看,基本操作如下
key * :查看存储内容
flushdb :清空数据库
如果redis不熟悉去看
undefined
SpringData也是和SpringBoot齐名的项目!
说明:在SpringBoot2.x之后,原来使用的jedis被替换为了lettuce
jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool连接池!【类似于BIO:同步阻塞IO】
lettuce:采用netty【异步请求,性能更高点】,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数量了【类似于NIO:同步非阻塞IO】
异步请求一般都需要序列化
源码分析:
@Bean//当这个Bean不存在的时候,这个类就生效//这就说明,我们可以自己定义一个redisTemplate来替换这个默认的!@ConditionalOnMissingBean(name="redisTemplate")@ConditionalOnSingleCandidate(RedisConnectionFactory.class)publicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory){//默认的RedisTemplate没有过多的设置,redis,对象都是需要序列化的!//两个泛型都是Object类型,我们后面使用需要强制转换:我们需要的类型<String,Object>RedisTemplate<Object,Object>template=newRedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);returntemplate;}@Bean@ConditionalOnMissingBean//由于String是Redis最常用的类型,所以说单独提出来了一个Bean@ConditionalOnSingleCandidate(RedisConnectionFactory.class)publicStringRedisTemplatestringRedisTemplate(RedisConnectionFactoryredisConnectionFactory){StringRedisTemplatetemplate=newStringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);returntemplate;}
上手测试【默认的RedisTemplate了解】
1.导入依赖
<!--操作redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--上面redis不兼容时候,可以换成jedis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency>
2.配置连接
#SpringBoot所有的配置类,都有一个自动配置类RedisAutoConfiguration#自动配置类都会绑定一个properties配置文件RedisPropertiesspring:redis:host:127.0.0.1#Redis服务器连接端口port:6379#Redis数据库索引(默认为0)database:0#Redis服务器连接密码(默认为空)password:#连接池最大连接数(使用负值表示没有限制)pool:max-active:200#连接池最大阻塞等待时间(使用负值表示没有限制)max-wait:-1#连接池中的最大空闲连接max-idle:10#连接池中的最小空闲连接min-idle:0#连接超时时间(毫秒)timeout:1000
3.测试
实际开发中我们都不会用这种原生的方式来编写代码
一般我们会将这些常用的操作编写成工具类:redisUtils【后面就会有】
前面还有jdbcUtils和MybatisUtils等
@SpringBootTestclassRedis03SpringbootApplicationTests{//注入RedisAutoConfiguration里面配置的类@AutowiredpublicRedisTemplateredisTemplate;@TestvoidcontextLoads(){//redisTemplate:操作我们的数据库,api和我们的是一样的//opsForValue:操作字符串类似String//opsForList:操作List//除了基本的操作,我们常用的方法都可以直接通过redisTemplate进行操作//比如事务和基本的CRUD//获取redis的连接对象,就可以操作数据库的连接了【一般很少来用】/*RedisConnectionconnection=redisTemplate.getConnectionFactory().getConnection();connection.flushDb();connection.flushAll();*/redisTemplate.opsForValue().set("kami","g1x");System.out.println(redisTemplate.opsForValue().get("kami"));}}
4.结果
问题:写到中文的时候,springboot是正常的,但是从redis中的redis.cli.exe运行keys *
会出来乱码
解决方法:默认的RedisTemplate没有过多的设置,redis,对象都是需要序列化的!
这是默认的序列化配置
默认序列化方式是JDK序列化
6.这时候我们就需要自己来写配置类
自己写了后,原来默认的RedisTemplate就会失效
创建一个config
@ConfigurationpublicclassRedisConfig{//编写我们自己的RedisTemplate@BeanpublicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory){RedisTemplate<String,Object>template=newRedisTemplate<>();//这里面到底怎么配置看后面template.setConnectionFactory(redisConnectionFactory);returntemplate;}}
上手测试【自定义的RedisTemplate——实际一般使用】
1.先创建一个pojo,user
//将它变为组件,方便调用@Component@Data@AllArgsConstructor@NoArgsConstructorpublicclassUser{privateStringname;privateIntegerage;}
2.测试类写序列化json对象操作【这里默认的序列化是JDK序列化】
@Testpublicvoidtest()throwsJsonProcessingException{//真实开发中一般都使用json来传递对象,所以要序列化jsonUseruser=newUser("葛",3);//所以要序列化成json对象【变成了json字符串】StringjsonUser=newObjectMapper().writeValueAsString(user);redisTemplate.opsForValue().set("user",jsonUser);System.out.println(redisTemplate.opsForValue().get("user"));}
如果不用上面的序列化json对象操作会报错!
String jsonUser = new ObjectMapper().writeValueAsString(user);
下面是关于对象的保存,但是一般都是用json对象
解决方法:在实体类中序列化即可【在企业中,我们所有的pojo都会序列化!SpringBoot】
//将它变为组件,方便调用@Component@Data@AllArgsConstructor@NoArgsConstructorpublicclassUserimplementsSerializable{privateStringname;privateIntegerage;}
3.刚才测试的是默认的序列化(JDK),这时候我们自己写其他方式的序列化
创建一个config
//这里面到底怎么配置看后面Jackson2JsonRedisSerializer<Object>objectJackson2JsonRedisSerializer=newJackson2JsonRedisSerializer<Object>();//配置具体的序列化template.setKeySerializer(objectJackson2JsonRedisSerializer);
多种序列化方式
写法例子
自己写很费劲,用已经写好的例子即可
连接中有不同地方,复制连接中importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterxml.jackson.databind.ObjectMapper;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.Jackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;importjava.rmi.UnknownHostException;/***@authorzhangzhixi*/@ConfigurationpublicclassRedisConfig{@Bean@SuppressWarnings("all")publicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory)throwsUnknownHostException{//自定义StringObjectRedisTemplate<String,Object>template=newRedisTemplate();template.setConnectionFactory(redisConnectionFactory);//Json序列化配置Jackson2JsonRedisSerializer<Object>objectJackson2JsonRedisSerializer=newJackson2JsonRedisSerializer<Object>(Object.class);//ObjectMapper转译ObjectMapperobjectMapper=newObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper);//String的序列化StringRedisSerializerstringRedisSerializer=newStringRedisSerializer();//key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);//hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);//value序列化方式采用jacksontemplate.setValueSerializer(objectJackson2JsonRedisSerializer);//hash的value采用jacksontemplate.setHashValueSerializer(objectJackson2JsonRedisSerializer);template.afterPropertiesSet();returntemplate;}}
企业中直接拿去使用即可
编写工具类
packagecom.kami.utils;/***@authorzhangzhixi*@date2021/3/123:33*/importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Component;importorg.springframework.util.CollectionUtils;importjava.util.List;importjava.util.Map;importjava.util.Set;importjava.util.concurrent.TimeUnit;/***@authormxz*/@ComponentpublicfinalclassRedisUtil{@AutowiredprivateRedisTemplate<String,Object>redisTemplate;/***指定缓存失效时间**@paramkey键*@paramtime时间(秒)*@return*/publicbooleanexpire(Stringkey,longtime){try{if(time>0){redisTemplate.expire(key,time,TimeUnit.SECONDS);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***根据key获取过期时间**@paramkey键(不能为Null)*@return时间(秒)返回0代表永久有效*/publiclonggetExpire(Stringkey){returnredisTemplate.getExpire(key,TimeUnit.SECONDS);}/***判断key是否存在**@paramkey键(不能为Null)*@returntrue存在false不存在*/publicbooleanhashKey(Stringkey){try{returnredisTemplate.hasKey(key);}catch(Exceptione){e.printStackTrace();returnfalse;}}/***删除缓存**@paramkey可以传一个值或多个*/publicvoiddel(String...key){if(key!=null&&key.length>0){redisTemplate.delete(key[0]);}else{redisTemplate.delete(CollectionUtils.arrayToList(key));}}//==================================String====================================/***普通缓存获取**@paramkey键*@return值*/publicObjectget(Stringkey){returnkey==null?null:redisTemplate.opsForValue().get(key);}/***普通缓存放入**@paramkey键*@paramvalue值*@returntrue成功false失败*/publicbooleanset(Stringkey,Objectvalue){try{redisTemplate.opsForValue().set(key,value);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***普通缓存放入并设置时间**@paramkey键*@paramvalue值*@paramtime时间(秒)time>0若time<=0将设置无限期*@returntrue成功false失败*/publicbooleanset(Stringkey,Objectvalue,longtime){try{if(time>0){redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);}else{set(key,value);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***递增**@paramkey键*@paramdelta要增加几(大于0)*@return*/publiclongincr(Stringkey,longdelta){if(delta<0){thrownewRuntimeException("递增因子必须大于0");}returnredisTemplate.opsForValue().increment(key,delta);}/***递减**@paramkey键*@paramdelta要减少几(小于0)*@return*/publiclongdecr(Stringkey,longdelta){if(delta<0){thrownewRuntimeException("递减因子必须大于0");}returnredisTemplate.opsForValue().decrement(key,delta);}//================================Map=================================/***HashGet**@paramkey键不能为null*@paramitem项不能为null*/publicObjecthget(Stringkey,Stringitem){returnredisTemplate.opsForHash().get(key,item);}/***获取hashKey对应的所有键值**@paramkey键*@return对应的多个键值*/publicMap<Object,Object>hmget(Stringkey){returnredisTemplate.opsForHash().entries(key);}/***HashSet**@paramkey键*@parammap对应多个键值*/publicbooleanhmset(Stringkey,Map<String,Object>map){try{redisTemplate.opsForHash().putAll(key,map);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***HashSet并设置时间**@paramkey键*@parammap对应多个键值*@paramtime时间(秒)*@returntrue成功false失败*/publicbooleanhmset(Stringkey,Map<String,Object>map,longtime){try{redisTemplate.opsForHash().putAll(key,map);if(time>0){expire(key,time);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***向一张hash表中放入数据,如果不存在将创建**@paramkey键*@paramitem项*@paramvalue值*@returntrue成功false失败*/publicbooleanhset(Stringkey,Stringitem,Objectvalue){try{redisTemplate.opsForHash().put(key,item,value);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***向一张hash表中放入数据,如果不存在将创建**@paramkey键*@paramitem项*@paramvalue值*@paramtime时间(秒)注意:如果已存在的hash表有时间,这里将会替换原有的时间*@returntrue成功false失败*/publicbooleanhset(Stringkey,Stringitem,Objectvalue,longtime){try{redisTemplate.opsForHash().put(key,item,value);if(time>0){expire(key,time);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***删除hash表中的值**@paramkey键不能为null*@paramitem项可以使多个不能为null*/publicvoidhdel(Stringkey,Object...item){redisTemplate.opsForHash().delete(key,item);}/***判断hash表中是否有该项的值**@paramkey键不能为null*@paramitem项不能为null*@returntrue存在false不存在*/publicbooleanhHasKey(Stringkey,Stringitem){returnredisTemplate.opsForHash().hasKey(key,item);}/***hash递增如果不存在,就会创建一个并把新增后的值返回**@paramkey键*@paramitem项*@paramby要增加几(大于0)*/publicdoublehincr(Stringkey,Stringitem,doubleby){returnredisTemplate.opsForHash().increment(key,item,by);}/***hash递减**@paramkey键*@paramitem项*@paramby要减少记(小于0)*/publicdoublehdecr(Stringkey,Stringitem,doubleby){returnredisTemplate.opsForHash().increment(key,item,-by);}//============================set=============================/***根据key获取Set中的所有值**@paramkey键*/publicSet<Object>sGet(Stringkey){try{returnredisTemplate.opsForSet().members(key);}catch(Exceptione){e.printStackTrace();returnnull;}}/***根据value从一个set中查询,是否存在**@paramkey键*@paramvalue值*@returntrue存在false不存在*/publicbooleansHasKey(Stringkey,Objectvalue){try{returnredisTemplate.opsForSet().isMember(key,value);}catch(Exceptione){e.printStackTrace();returnfalse;}}/***将数据放入set缓存**@paramkey键*@paramvalues值可以是多个*@return成功个数*/publiclongsSet(Stringkey,Object...values){try{returnredisTemplate.opsForSet().add(key,values);}catch(Exceptione){e.printStackTrace();return0;}}/***将set数据放入缓存**@paramkey键*@paramtime时间(秒)*@paramvalues值可以是多个*@return成功个数*/publiclongsSetAndTime(Stringkey,longtime,Object...values){try{Longcount=redisTemplate.opsForSet().add(key,values);if(time>0){expire(key,time);}returncount;}catch(Exceptione){e.printStackTrace();return0;}}/***获取set缓存的长度**@paramkey键*/publiclongsGetSetSize(Stringkey){try{returnredisTemplate.opsForSet().size(key);}catch(Exceptione){e.printStackTrace();return0;}}/***移除值为value的**@paramkey键*@paramvalues值可以是多个*@return移除的个数*/publiclongsetRemove(Stringkey,Object...values){try{Longcount=redisTemplate.opsForSet().remove(key,values);returncount;}catch(Exceptione){e.printStackTrace();return0;}}//===============================list=================================/***获取list缓存的内容**@paramkey键*@paramstart开始*@paramend结束0到-1代表所有值*/publicList<Object>lGet(Stringkey,longstart,longend){try{returnredisTemplate.opsForList().range(key,start,end);}catch(Exceptione){e.printStackTrace();returnnull;}}/***获取list缓存的长度**@paramkey键*/publiclonglGetListSize(Stringkey){try{returnredisTemplate.opsForList().size(key);}catch(Exceptione){e.printStackTrace();return0;}}/***通过索引获取list中的值**@paramkey键*@paramindex索引index>=0时,0表头,1第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推*/publicObjectlGetIndex(Stringkey,longindex){try{returnredisTemplate.opsForList().index(key,index);}catch(Exceptione){e.printStackTrace();returnnull;}}/***将list放入缓存**@paramkey键*@paramvalue值*/publicbooleanlSet(Stringkey,Objectvalue){try{redisTemplate.opsForList().rightPush(key,value);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***将list放入缓存**@paramkey键*@paramvalue值*@paramtime时间(秒)*/publicbooleanlSet(Stringkey,Objectvalue,longtime){try{redisTemplate.opsForList().rightPush(key,value);if(time>0){expire(key,time);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***将list放入缓存**@paramkey键*@paramvalue值*@return*/publicbooleanlSet(Stringkey,List<Object>value){try{redisTemplate.opsForList().rightPushAll(key,value);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***将list放入缓存**@paramkey键*@paramvalue值*@paramtime时间(秒)*@return*/publicbooleanlSet(Stringkey,List<Object>value,longtime){try{redisTemplate.opsForList().rightPushAll(key,value);if(time>0){expire(key,time);}returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***根据索引修改list中的某条数据**@paramkey键*@paramindex索引*@paramvalue值*@return*/publicbooleanlUpdateIndex(Stringkey,longindex,Objectvalue){try{redisTemplate.opsForList().set(key,index,value);returntrue;}catch(Exceptione){e.printStackTrace();returnfalse;}}/***移除N个值为value**@paramkey键*@paramcount移除多少个*@paramvalue值*@return移除的个数*/publiclonglRemove(Stringkey,longcount,Objectvalue){try{Longremove=redisTemplate.opsForList().remove(key,count,value);returnremove;}catch(Exceptione){e.printStackTrace();return0;}}//===============================HyperLogLog=================================publiclongpfadd(Stringkey,Stringvalue){returnredisTemplate.opsForHyperLogLog().add(key,value);}publiclongpfcount(Stringkey){returnredisTemplate.opsForHyperLogLog().size(key);}publicvoidpfremove(Stringkey){redisTemplate.opsForHyperLogLog().delete(key);}publicvoidpfmerge(Stringkey1,Stringkey2){redisTemplate.opsForHyperLogLog().union(key1,key2);}}
我们真实的分发中,或者在你们的公司,一般都可以看到一个公司自己封装RedisUtil
转到测试类
@SpringBootTestclassRedis02SpringbootApplicationTests{@Autowired//指定我们自己定义的redis序列化配置privateRedisTemplate<String,Object>redisTemplate;@AutowiredprivateRedisUtilredisUtil;@Testvoidtest1(){//清空数据库redisTemplate.getConnectionFactory().getConnection().flushDb();Useruser=newUser("zhangsha",23);redisUtil.set("user",user);System.out.println(redisUtil.get("user"));}}
这时候注入的
RedisTemplate
需要导入的是我们的结果就是输出前加了转译【不再是乱码】
关于“SpringBoot整合Redis案例分析”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“SpringBoot整合Redis案例分析”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注恰卡编程网行业资讯频道。
推荐阅读
-
php如何让Swoole/Pool进程池实现Redis持久连接
php如何让Swoole/Pool进程池实现Redis持久连接本篇...
-
php操作redis大全记录
php连接redis测试˂?php$redis=newRedis();$redis-˃conne...
-
PHP经典高级工程师面试题
1.PHP如何实现不用自带的cookie函数为客户端下发cookie。对于分布式系统,如何来保存session值...
-
PHP操作Redis数据库
-
php利用redis防止商品超发来限制抢购,简单又实用
-
php如何实现秒杀功能?php+redis模拟简单抢购场景,快来看看吧
-
PHP高级工程师面试题
-
Laravel结合Redis发送邮箱验证码
-
使用redis缓存实现多服务器PHP sessions共享
-
PHP用redis的有序集合zset实现延迟队列