Springboot中使用Redis
本文内容纲要:
一、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;
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