1.Redis介绍
Redis技术栈目前广泛使用于开发领域,掌握Redis技术栈与Springboot的集成至关重要。Redis是目前业界使用最广泛的内存数据存储。相比memcached,Redis支持更丰富的数据结构,例如hashes, lists, sets等,同时支持数据持久化。除此之外,Redis还提供一些类数据库的特性,比如事务,HA,主从库。可以说Redis兼具了缓存系统和数据库的一些特性,因此有着丰富的应用场景。
1.1Redis的安装与启动
安装自己的redis,并启动redis,这一章节前面有介绍过,不做过多的描述了,不会的可以自行百度。
1.2Redis的安装目录讲解
这一块主要是了解一下*.conf:配置文件,redis的相关功能和属性都是在这个文件进行配置的(监听端口、主从复制、哨兵、cluster集群等等)。
1.3Redis命令行操作练习
命令就不过多的说了,参考http://doc.redisfans.com/进行练习即可。
2.Springboot集成Redis步骤与代码详解
2.1Springboot集成Redis,pom文件的配置
这里多说一下:在springboot2之后,redis默认集成的是lettuce.1.5的版本默认采用的连接池技术是jedis , 2.0以上版本默认连接池是lettuce. 1.5版本的springboot集成redis与2.0有所不同(核心配置类的书写也有很大的区别),主要是因为连接池技术使用的差异,这里主要介绍springboot的2.x版本。
<!--redis配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--进行redisTemplate配置时需要此包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
题外话:Jedis与Lettuce的区别
如果你在网上搜索Redis 的Java客户端,你会发现,大多数文献介绍的都是 Jedis。不可否认,Jedis是一个优秀的基于Java语言的Redis客户端。但是,其不足也很明显:Jedis在实现上是直接连接Redis-Server,在多个线程间共享一个Jedis实例时是线程不安全的,如果想要在多线程场景下使用Jedis,需要使用连接池,每个线程都使用自己的Jedis实例,当连接数量增多时,会消耗较多的物理资源。与Jedis相比,Lettuce则完全克服了其线程不安全的缺点:Lettuce是一个可伸缩的线程安全的Redis客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀Netty NIO框架构建,支持Redis的高级功能,如Sentinel,集群,流水线,自动重新连接和Redis数据模型。
2.2application.properties文件配置
# REDIS (Redis 配置)
# 连接工厂使用的数据库索引
spring.redis.database= 0
# Redis服务器主机
spring.redis.host=127.0.0.1
# redis服务器端口
spring.redis.port= 6379
# 登录redis服务器的密码
spring.redis.password=
# 给定时间池可以分配的最大连接数 使用负值为无限制
spring.redis.pool.max-active= 8
# 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
spring.redis.pool.max-wait= -1
# 连接池中的最大空闲连接 使用负值来表示无限数量的空闲连接
spring.redis.pool.max-idle= 8
# 连接池中的最小空闲连接 此设置只有在正值时才有效果
spring.redis.pool.min-idle= 0
# 连接超时(毫秒)
spring.redis.timeout=30000
2.3redis核心集成配置类
这个今天所有学习中的重点,我也跟着做了详细的注释说明,希望大家能理解并自己手动敲出来!
package com.lengmo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* Redis的核心配置类,这个类提供了两个方法(其实提供了两个bean,这两个bean会加载到spring的context里边,供使用者进行调用)
*/
@Configuration//这个标签,通常与@bean结合使用,当@bean使用到该类的方法上,代表将该方法做为一个bean交给了spring的context
@EnableCaching//允许我们使用缓存
public class RedisConfig {
@Bean//此时,将我们的redisTemplate加载到了我们的spring的上下文中,applicationContext
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
//1.初始化一个redisTemplate
RedisTemplate<String,Object> redisTemplate=new RedisTemplate<String,Object>();
//2.序列话(一般用于key值)
RedisSerializer<String> redisSerializer=new StringRedisSerializer();
//3.引入json串的转化类(一般用于value的处理)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper=new ObjectMapper();
//3.1设置objectMapper的访问权限
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//3.2指定序列化输入类型,就是将数据库里的数据按照一定类型存储到redis缓存中。
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//最近升级SpringBoot,发现enableDefaultTyping方法过期过期了。可以使用下面的方法代替
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//4.创建链接
redisTemplate.setConnectionFactory(factory);
//4.1redis key值序列化
redisTemplate.setKeySerializer(redisSerializer);
//4.2value序列化,因为我们的value大多是通过对象转化过来的,所以使用jackson2JsonRedisSerializer
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//4.3value序列化,hashmap的序列话
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory){
//1.序列话(一般用于key值)
RedisSerializer<String> redisSerializer=new StringRedisSerializer();
//2.引入json串的转化类(一般用于value的处理)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper=new ObjectMapper();
//2.1设置objectMapper的访问权限
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//2.2指定序列化输入类型,就是将数据库里的数据按照一定类型存储到redis缓存中。
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//最近升级SpringBoot,发现enableDefaultTyping方法过期过期了。可以使用下面的方法代替
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//3.序列话配置,乱码问题解决以及我们缓存的时效性
RedisCacheConfiguration config=RedisCacheConfiguration.defaultCacheConfig().
entryTtl(Duration.ofSeconds(1000)).//缓存时效性设置
serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).//key序列化
serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).//value序列化
disableCachingNullValues();//空值不存入缓存
//4.创建cacheManager链接并设置属性
RedisCacheManager cacheManager= RedisCacheManager.builder(factory).cacheDefaults(config).build();
return cacheManager;
}
}
3.Springboot集成Redis代码实战
package com.lengmo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/redis")
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/getString")
@Cacheable(value = "springbootredis",key = "#root.methodName")
public String getString(){
String str="hello redis";
System.out.println("没有读取缓存,进入方法返回的值");
return str;
}
@RequestMapping("/setValue")
public String setValue(){
redisTemplate.opsForValue().set("myName","zhangsan");
stringRedisTemplate.opsForValue().set("yourName","lisi");
return "这里分别用redisTemplate和stringRedisTemplate设置了两个键值,方便后面验证一个问题";
}
@RequestMapping("/getValue")
public String getValue(){
String str1= (String) redisTemplate.opsForValue().get("myName");
// String str2= (String) redisTemplate.opsForValue().get("yourName");
String str3=stringRedisTemplate.opsForValue().get("myName");
String str4=stringRedisTemplate.opsForValue().get("yourName");
return "验证取值的问题,str1="+str1+"===,str2="+" "+"===,str3="+str3+"===,str4="+str4;
}
}
3.1cacheManage的练习使用(***重点)
3.2RedisTemplate 和 StringRedisTemplate的使用
两者的关系是StringRedisTemplate继承RedisTemplate。
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
其实他们两者之间的区别主要在于他们使用的序列化类:RedisTemplate使用的是JdkSerializationRedisSerializer存入数据会将数据先序列化成字节数组然后在存入Redis数据库。 StringRedisTemplate使用的是StringRedisSerializer
使用时注意事项:
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据 的时候,那么你就使用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从 Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。
这一块的理解参看RedisTestController 里面的实战,多测试几次就明白这个的区别了。
3.3补充知识
RedisTemplate常用操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作有序set
StringRedisTemplate常用操作
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间
stringRedisTemplate.boundValueOps("test").increment(-1);//val做-1操作
stringRedisTemplate.opsForValue().get("test")//根据key获取缓存中的val
stringRedisTemplate.boundValueOps("test").increment(1);//val +1
stringRedisTemplate.getExpire("test")//根据key获取过期时间
stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)//根据key获取过期时间并换算成指定单位
stringRedisTemplate.delete("test");//根据key删除缓存
stringRedisTemplate.hasKey("546545");//检查key是否存在,返回boolean值
stringRedisTemplate.opsForSet().add("red_123", "1","2","3");//向指定key中存放set集合
stringRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS);//设置过期时间
stringRedisTemplate.opsForSet().isMember("red_123", "1")//根据key查看集合中是否存在指定数据
stringRedisTemplate.opsForSet().members("red_123");//根据key获取set集合
4.对controller里面的方法验证
1.理解缓存的作用
2.往redis里面写数据
3.从redis里面取数据