目录
Redis缓存服务器
1.业务说明
2.关于缓存机制说明
说明: 缓存中的数据都是数据库中的记录. 引入缓存机制之后,主要的目的为了降低用户访问物理设备的频次.提高服务器响应效率.
维度说明:
1).开发语言: C语言开发
2).数据结构问题: K-V结构 map/properties key不能重复
3).内存数据 断电及擦除: 定期将内存数据持久化操作
4).内存资源有效: 如何有效的维护内存大小? 定期清理内存. LRU算法/LFU算法/TLL算法
3.Redis介绍
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
速度: 读: 11.2万次/秒 写: 8.6万次/秒 平均10万次/秒
4.Redis安装
4.1 上传Redis安装包
4.2 解压文件
tar -xvf redis-5.0.4.tar.gz
4.2 安装redis
步骤: 进入redis根目录中
命令1: make
命令2: make install
4.3修改redis配置文件
vim后显示行号:set nu
命令: vim redis.conf
展现行号:
1).关闭IP绑定
2).关闭保护模式
3).开启后台运行
4.4 Redis启动命令
1).启动redis命令
redis-server redis.conf
2).进入redis客户端
redis-cli -p 6379
3).关闭redis
redis-cli -p 6379 shutdown
5.Redis入门案例
5.1 导入jar包
<!--spring整合redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
5.2 入门案例
package com.jt.redis;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.params.Params;
import redis.clients.jedis.params.SetParams;
public class TestRedis {
/**
* 1.redis配置文件3处修改
* 2.Linux系统防火墙
* 3.检查redis启动方式 redis-server redis.conf
* */
@Test
public void testSet() throws InterruptedException {
String host = "192.168.126.129";
int port = 6379;
Jedis jedis = new Jedis(host,port);
//命令怎么敲,代码怎么写
jedis.set("2011", "redis入门案例");
System.out.println(jedis.get("2011"));
jedis.flushAll();
//测试是否存在
if(jedis.exists("2011")){
jedis.del("2011");
}else{
jedis.set("num", "100");
//自增1
jedis.incr("num");
jedis.expire("num", 20);
Thread.sleep(2000);
//检查超时时间
System.out.println(jedis.ttl("num"));
//取消超时时间
jedis.persist("num");
}
}
//有时我们可能会为数据添加超时时间
//原子性问题: 有时业务要求要么同时完成,要么同时失败
@Test
public void testSetEx(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
//jedis.set("a","aa");
//服务器异常
//jedis.expire("a",60);
jedis.setex("a", 20, "100");
System.out.println(jedis.get("a"));
}
/**
* 需求1:如果该数据不存在时,才会赋值.
* 需求2: 如果数据存在时,进行修改, 并且为他设定超时时间 满足原子性要求.
*
*/
@Test
public void testSetNX(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.set("a", "111");
jedis.setnx("a", "123");
System.out.println(jedis.get("a"));
SetParams params = new SetParams();
params.xx().ex(20);
jedis.set("b", "bb", params);
}
//默认hash是无序的
@Test
public void testHash(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.hset("user", "id", "100");
jedis.hset("user", "name", "101");
jedis.hset("user", "age", "18");
System.out.println(jedis.hkeys("user"));
}
//队列:先进先出 方向相反
//栈: 先进后出 方向相同 注意可变参数类型
@Test
public void testList(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.lpush("list", "1","2","3","4");
System.out.println(jedis.rpop("list"));
}
@Test
public void testTx(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
//开启事务
Transaction transaction = jedis.multi();
try {
transaction.set("a", "a");
transaction.set("b", "b");
transaction.set("b", "b");
//提交事务
transaction.exec();
}catch (Exception e){
transaction.discard();
}
}
}
6.SpringBoot整合Redis
6.1 编辑pro配置文件
6.2 编辑配置类
package com.jt.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.Jedis;
@Configuration //标识为一个配置类, 一般整合第三方
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Bean //将该方法的返回值,交给Spring容器管理
public Jedis jedis(){
return new Jedis(host,port);
}
}
7.AOP缓存的实现
7.1 自定义注解
@Target({ElementType.METHOD}) //标识注解使用在方法中
@Retention(RetentionPolicy.RUNTIME) //什么时期有效
public @interface CacheFind {
//key-value方法的返回值
String key(); //要求用户必须指定key
int seconds() default -1; //设定超时时间 -1 无需超时
}
7.2 使用缓存注解
7.3 编辑RedisAOP
@Component //将对象交给Spring容器管理
@Aspect //标识AOP切面
public class RedisAOP {
@Autowired
private Jedis jedis;
//通知选择: 是否控制目标方法是否执行. 环绕通知
//切入点表达式: 控制注解 @annotation(语法....)
/**
* 需求: 如何动态获取注解中的属性值.
* 原理: 反射机制
* 获取目标对象~~~~~获取方法对象~~~获取注解 原始API
*
* @param joinPoint
* @return
* @throws Throwable
*
* 向上造型: 父类 = 子类
* 向下造型: 子类 = (强制类型转化)父类
*
* AOP中的语法规范1.:
* 如果通知方法有参数需要添加,则joinPoint 必须位于第一位.
* 报错信息: error at ::0 formal unbound in pointcut
* AOP中的语法规范3:
* 如果需要动态接受注解对象,则在切入点表达式中直接写注解参数名称即可
* 虽然看到的是名称,但是解析时变成了包名.类型
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) throws Throwable {
Object result = null;
//1.获取key="ITEM_CAT_PARENTID"
String key = cacheFind.key();
//2.动态拼接key 获取参数信息
String args = Arrays.toString(joinPoint.getArgs());
key += "::" + args;
//3.redis缓存实现
if(jedis.exists(key)){
String json = jedis.get(key);
//target标识返回值类型????
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class returnType = methodSignature.getReturnType();
result = ObjectMapperUtil.toObject(json, returnType);
System.out.println("AOP缓存查询!!!");
}else{
//查询数据库 执行目标方法
result = joinPoint.proceed();
String json = ObjectMapperUtil.toJSON(result);
if(cacheFind.seconds()>0)
jedis.setex(key,cacheFind.seconds(),json);
else
jedis.set(key, json);
System.out.println("AOP查询数据库");
}
return result;
}