一、Redis基本概述
1.Redis简介
Redis 是一个高性能的 Key-Value 开源数据库, 是一个非关系型的数据库,是为了解决高并发、高扩展,大数据存储等一系列的问题而产生的数据库解决方案。但它不能替代关系型数据库,只能作为特定环境下的扩充。
2.为什么用Redis作为缓存
支持高可用: Redis 支持 master\slave 主\从机制、sentinal 哨兵模式、cluster 集群模式,大大保证了 Redis 运行的稳定和高可用性。
支持多种数据结构: Redis 不仅支持简单的 Key/Value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。
支持数据持久化: 可以将内存中的数据持久化在磁盘中,当宕机或者故障重启时,可以再次加载进如 Redis,从而不会或减少数据的丢失。
生态完善: Redis 已成为业界内缓存的首选目标,所以很多语言和工具对其支持。
3.Redis支持的数据类型
Redis 支持的数据结构类型包括:
字符串(string)
哈希表(hash)
列表(list)
集合(set)
有序集合(zset)
为了保证读取效率,Redis 把数据对象存储在内存中,并支持周期性的把更新的数据写入磁盘文件中。而且它还提供了交集和并集,以及一些不同方式排序的操作。
一、使用redis缓存
1.导入redis依赖
<!-- redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.修改项目启动类,添加@EnableCaching注解,开启缓存功能
@Slf4j
@EnableCaching //开启springcache注解方式
@SpringBootApplication
@ServletComponentScan
@EnableTransactionManagement
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功。。。");
}
}
3.配置redis数据库,将配置信息写入yml文件中(我用的是Linux虚拟机中的redis数据库)
spring:
redis:
host: 192.168.200.128 #主机ip
port: 6379 #端口号
database: 0 #存入的数据库
password: 123456 #数据库密码
4.创建redis配置类
/**
* Redis 配置类
*/
@Configuration
public class RedisConfig {
/**
* 配置缓存管理器
* @param factory Redis 线程安全连接工厂
* @return 缓存管理器
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
// 生成两套默认配置,通过 Config 对象即可对缓存进行自定义配置
RedisCacheConfiguration cacheConfig1 = RedisCacheConfiguration.defaultCacheConfig()
// 设置过期时间 10 分钟
.entryTtl(Duration.ofMinutes(10))
// 设置缓存前缀
.prefixKeysWith("cache:user:")
// 禁止缓存 null 值
.disableCachingNullValues()
// 设置 key 序列化
.serializeKeysWith(keyPair())
// 设置 value 序列化
.serializeValuesWith(valuePair());
RedisCacheConfiguration cacheConfig2 = RedisCacheConfiguration.defaultCacheConfig()
// 设置过期时间 30 秒
.entryTtl(Duration.ofSeconds(30))
.prefixKeysWith("cache:admin:")
.disableCachingNullValues()
.serializeKeysWith(keyPair())
.serializeValuesWith(valuePair());
// 返回 Redis 缓存管理器
return RedisCacheManager.builder(factory)
.withCacheConfiguration("user", cacheConfig1)
.withCacheConfiguration("admin", cacheConfig2)
.build();
}
/**
* 配置键序列化
* @return StringRedisSerializer
*/
private RedisSerializationContext.SerializationPair<String> keyPair() {
return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
}
/**
* 配置值序列化,使用 GenericJackson2JsonRedisSerializer 替换默认序列化
* @return GenericJackson2JsonRedisSerializer
*/
private RedisSerializationContext.SerializationPair<Object> valuePair() {
return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
}
}
5.操作数据库,SpringBoot提供了两个bean来操作redis,分别是RedisTemplate 和 StringRedisTemplate,这两者的主要区别在于:RedisTemplate,存入数据会将数据先序列化成字节数组然后在存入Redis数据库;StringRedisTemplate使用的是StringRedisSerializer。这里我使用的是RedisTemplate。如下(短信验证码缓存案例):
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
//1.首先要加入RedisTemplate注解
@Autowired
private RedisTemplate redisTemplate;
/**
* 发送短信验证码
*
* @param user
* @param session
* @return
*/
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession session) {
//获取手机号
String phone = user.getPhone();
if (StringUtils.isNotEmpty(phone)) {
//生成随机的四位验证码
String code = ValidateCodeUtils.generateValidateCode(4).toString();
log.info("code={}", code);
//调用阿里云提供的短信服务API,完成发送短信
// SMSUtils.sendMessage("阿里云短信测试","SMS_154950909",phone,code);
//将生成的验证码保存起来Session
// session.setAttribute(phone, code);
//2.将生成的验证码缓存到redis中,并设置有效期1分钟
redisTemplate.opsForValue().set(phone,code,1, TimeUnit.MINUTES);
return R.success("短信发送成功");
}
return R.error("短信发送失败");
}
/**
* 移动端登录
*
* @param map
* @param session
* @return
*/
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session) {
System.out.println(map);
//获取手机号
String phone = map.get("phone").toString();
//获取验证码
String code = map.get("code").toString();
//3.从redis中获取缓存的验证码
Object codeInSession = redisTemplate.opsForValue().get(phone);
//进行验证码对比
if (codeInSession != null && codeInSession.equals(code)) {
//如果能够对比,说明登录成功
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getPhone, phone);
User user = userService.getOne(queryWrapper);
if (user == null) {
//判断当前手机号是否为新用户,如果是,则自动注册
user = new User();
user.setPhone(phone);
user.setStatus(1);
userService.save(user);
}
session.setAttribute("user", user.getId());
return R.success(user);
}
//4.如果用户登录成功就删除redis缓存的验证码
redisTemplate.delete(phone);
return R.error("登录失败");
}
}
二、使用SpringCache的注解
1.注解说明及使用方法:
2.常用注解的配置参数:
value: 缓存管理器中配置的缓存的名称,这里可以理解为一个组的概念,缓存管理器中可以有多套缓存配置,每套都有一个名称,类似于组名,这个可以配置这个值,选择使用哪个缓存的名称,配置后就会应用那个缓存名称对应的配置。
key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。
condition: 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。
unless: 不缓存的条件,和 condition 一样,也是 SpEL 编写,返回 true 或者 false,为 true 时则不进行缓存。
3.操作案例,如下(用户案例):
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private CacheManager cacheManager;
@Autowired
private UserService userService;
/**
* CashePut:将方法返回值放入缓存
* value:缓存名称
* ksy:缓存的key
* @param user
* @return
*/
@CachePut(value = "userCache",key = "#user.id")
@PostMapping
public User save(User user){
userService.save(user);
return user;
}
/**
* CacheEvict:删除指定缓存
* value:缓存名称
* ksy:缓存的key
* @param id
*/
@CacheEvict(value = "userCache",key="#id")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
/**
* 修改后也要清除缓存
* @param user
* @return
*/
@CacheEvict(value = "userCache",key="#user.id")
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}
/**
* Cacheable:查询缓存中是否有数据,如果有则返回缓存中的数据,没有则查询数据库
* condition = "#result != null" 目的:查询出的数据不为空,才可以缓存
* unless:满足条件则不缓存
* @param id
* @return
*/
@Cacheable(value = "userCache",key = "#id",unless = "#result == null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}
/**
* 查询集合数据,如果缓存中存在,则从缓存中取出,否则就执行查询,将查询结果存入缓存
* @param user
* @return
*/
@Cacheable(value = "userCache",key = "#user.id +'_'+#user.name")
@GetMapping("/list")
public List<User> list(User user){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(user.getId() != null,User::getId,user.getId());
queryWrapper.eq(user.getName() != null,User::getName,user.getName());
List<User> list = userService.list(queryWrapper);
return list;
}
}