REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
在日常的javaweb开发过程中,无时无刻的都在使用数据库进行数据的存储,由于一般的系统中并不存在高并发的情况,所以在平常的开发中都没有什么问题。当业务需求中需要有一些高并发的情况,比如商品的抢购等的一些情景,使用数据库进行数据的查询和存储就会有很大的风险造成服务器宕机等情况,因为数据库是面向磁盘进行数据的读写。磁盘的读写速度相对较慢。这是我们就要选择一些nosql的数据存储方式。redis就是其中的一种。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
本文中会使用aop切面+注解实现手动缓存。
spring.redis.host=127.0.0.1
spring.redis.port=6379
简单的redis配置
RedisTemplate手动缓存,即使用RedisTemplate实现类操作。
/**
* 自定义注解类
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {
/**
* 过期时间,默认60s
* @return
*/
long expire() default 30 * 1000;
/**
* 缓存标识name
* @return
*/
String name() default "";
}
**
* @title: CacheAspect aop切面设置数据缓存
* @Author zzm
* @Date: 2022/4/4 16:00
* @Version 1.0
*/
@Aspect
@Component
public class CacheAspect {
@Autowired
private RedisUtils redisUtils;
/**
* 设置切点
*/
@Pointcut("@annotation(com.zzm.shop.cache.Cache)")
private void cache(){
}
@Around("cache()")
public Object toCache(ProceedingJoinPoint joinPoint){
try {
//设置存储格式
Signature signature = joinPoint.getSignature();
//类名
String className = joinPoint.getTarget().getClass().getSimpleName();
//方法名
String methodName = signature.getName();
//将传递过来的参数进行处理
//1、获取数据
Object[] args = joinPoint.getArgs();
//2、创建参数类型
Class[] parameterType = new Class[args.length];
//3、值
String params = "";
for (int i = 0; i < args.length; i++) {
if(args[i] != null){
parameterType[i] = args[i].getClass();
params += JSON.toJSONString(args[i]);
}
}
//可以不加密,选用
// if(!CommonUtil.isEmpty(params)){
// //加密,防止出现字符转义失败情况。
// params = SignUtil.toMD5(params);
// }
//获取controller对应的方法
Method method = signature.getDeclaringType().getMethod(methodName, parameterType);
//获取cache注解信息
Cache annotation = method.getAnnotation(Cache.class);
long expire = annotation.expire();
String name = annotation.name();
//组成redis中的key
String redisKey = name + "::" + className +"::"+ methodName +"::"+ params;
//获取key对应的值
String redisValue = redisUtils.get(redisKey);
if(!CommonUtil.isEmpty(redisValue)){
JSONObject jsonObject = JSONObject.parseObject(redisValue);
// System.out.println("从redis中获取"); //测试时
Map map = new HashMap(1);
map.put("data",jsonObject.get("data"));
return R.ok(map);
}
//执行查询数据库操作
Object proceed = joinPoint.proceed();
JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(proceed));
//数据结果查询成功后才会添加进缓存
if(jsonObject.getString("status").equals("200") && jsonObject.getString("data")!= null && !"".equals(jsonObject.getString("data"))){
redisUtils.set(redisKey,JSON.toJSONString(proceed),expire, TimeUnit.MILLISECONDS);
// System.out.println("数据存入缓存"); //测试时
}
return proceed;
}catch (Throwable throwable){
throwable.printStackTrace();
}
return R.error("系统错误!!"); //R统一返回结果
}
/**
* @title: RedisConfig
* @Author zzm
* @Date: 2022/4/4 15:59
* @Version 1.0
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂类
redisTemplate.setConnectionFactory(factory);
// 设置k-v的序列化方式
// Jackson2JsonRedisSerializer 实现了 RedisSerializer接口
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 还可设置很多的配置 ... ... (未设置就使用默认配置)
return redisTemplate;
}
}
/**
* @title: RedisUtils redis操作类
* @Author zzm
* @Date: 2022/4/4 16:07
* @Version 1.0
*/
@Service
public class RedisUtils {
@Autowired
private RedisTemplate<String,String> redisTemplate;
/**
* 写入缓存+过期时间
* @param key
* @param value
* @param expireTime
* @param timeUnit
* @return
*/
public boolean set( String key, String value, Long expireTime , TimeUnit timeUnit){
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set(key,value);
redisTemplate.expire(key,expireTime,timeUnit);
return true;
}
/**
* 通过key获取value
* @param key
* @return
*/
public String get(String key){
ValueOperations<String, String> operations = redisTemplate.opsForValue();
return operations.get(key);
}
/**
* 批量删除
* @param keys
* @return
*/
public boolean remove(final String... keys){
for(String key : keys){
if(redisTemplate.hasKey(key)){ //key存在就删除
redisTemplate.delete(key);
}
}
return true;
}
}
/**
* @title: UserController
* @Author zzm
* @Date: 2022/4/4 16:40
* @Version 1.0
*/
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@Cache(name = "selByPhone") //将需要缓存的接口添加@cache注解
@PostMapping("/selByPhone")
public Object selByPhone(@RequestParam("phone") String phone){
return userService.selByPhone(phone);
}
}