1.Redis缓存机制的介绍
说明:使用缓存的目的主要就是为了降低用户访问无论设备的频次,从缓存服务器中直接获取数据,快速的响应用户,提高整体的查询速度,用户体验更好
如何实现:
- 缓存机制采用的是K-V的数据存储结构,K必须唯一
- 使用C语言进行开发
- 缓存的运行环境是内存
- 内存断电及擦除,为了保证数据的安全性,实现持久化(写入磁盘)操作
- 内存中数据不能存的问题利用内存优化的算法(LRU)进行解决
2.Redis介绍
Redis是一个开源(DBS许可)的,内存中的数据结构存储系统,他可以用作数据库,缓存和消息中间件,他支持多种类型的数据结构,如字符串(String),散列表(hashes),列表(lists),集合(sets),有序集合(sorted sets)与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。
Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability).
速度快:
tomcat: 150-220/秒
nginx: 3-5万/秒
redis: 写 8.6万/秒 读 11.2万/秒 ~ 平均10万次/秒
3.Redis常规命令
要求:进入redis根目录中执行.
特点:redis每次启动时都会读取配置文件. 如果需要准备多台redis则需要准备多个配置文件
1.启动命令:redis-server redis.conf
redis没有开启后台运行效果
2.开启后台运行:redis-server redis.conf
3.检索Redis服务:ps -ef | grep redis
4.进入Redis客户端:redis-cli -p 端口号
5.关闭Redis
方式一:redis-cli -p 6379 shutdown
方式二:
4.Redis入门案例
4.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>
4.2编辑测试API
package com.jt.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
//@SpringBootTest //需要依赖spring容器,从容器中动态的获取对象
public class TestRedis {
/**
* 完成Redis入门案例测试
* 报错说明:
* 1.检查Linux防火墙
* 2.检查Redis3项配置
* 3.重启redis.
*/
@Test
public void test01(){
Jedis jedis = new Jedis("192.168.126.129",6379);
//1.向redis中保存数据
jedis.set("2004", "哈哈哈 今天下雨了 不负众望");
//2.从redis中获取数据
String value = jedis.get("2004");
System.out.println(value);
}
@Test
public void test02(){
Jedis jedis = new Jedis("192.168.126.129",6379);
//1.判断redis中是否存在key
if(jedis.exists("2004")){
//2.如果存在则设定超时时间
jedis.expire("2004", 100);
//3.线程暂停2秒
try {
Thread.sleep(2000);
//4.获取剩余的存活时间
Long time = jedis.ttl("2004");
System.out.println("还能活:"+time);
//5.撤销删除操作
jedis.persist("2004");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 需求说明:
* 1.redis.set操作,后面的操作会将之前的value覆盖
* 要求:如果key已经存在,则不允许赋值.
* 注意环境: 检查redis中是否有改数据.
* */
@Test
public void test03() {
//A 潘石屹 B 马云
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.flushAll(); //清空redis缓存
//如果key存在则不执行赋值操作.
jedis.setnx("boss", "潘石屹");
jedis.setnx("boss", "马云");
System.out.println(jedis.get("boss"));
}
/**
* 为数据添加超时时间.保证原子性操作
* 原子性: 一起完成一起回滚
* 锁机制: 保证原子性 死锁!!!!
* 小结: setnx 如果key存在则不赋值
* setex 保证原子性操作,并且添加超时时间.
* * */
@Test
public void test04() {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.setex("aaa", 20, "xxxxx"); //满足原子性需求.
}
/**
* 需求:
* 1.要求赋值操作时,如果数据已经存在则不允许赋值.
* 2.同时要求添加超时时间 并且满足原子性要求.
* private static final String XX = "xx"; 只有key存在时,才能赋值
* private static final String NX = "nx"; 只有key不存在时,赋值
* private static final String PX = "px"; 毫秒
* private static final String EX = "ex"; 秒
*/
@Test
public void test05() {
Jedis jedis = new Jedis("192.168.126.129", 6379);
SetParams setParams = new SetParams();
setParams.nx().ex(20);
jedis.set("AAA", "CCCCC", setParams); //原子性要求
System.out.println(jedis.get("AAA"));
}
/*测试hash数据类型*/
@Test
public void testHash() {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.hset("person", "name", "tomcat");
jedis.hset("person", "age", "100");
Map<String,String> map = jedis.hgetAll("person");
System.out.println(map);
}
@Test
public void testList() {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.lpush("list", "1","2","3","4");
String value = jedis.rpop("list");
System.out.println(value);
}
/**
* 实现Redis 事务控制
*/
@Test
public void testMulti() {
Jedis jedis = new Jedis("192.168.126.129", 6379);
Transaction transaction = jedis.multi();
try {
transaction.set("AAA", "XXX");
transaction.set("BBB", "XXX");
transaction.exec(); //提交事务
}catch (Exception exception){
exception.printStackTrace();
transaction.discard();//回滚事务
}
}
}
5.Springboot整合Redis
5.1编辑配置文件
redis.host=192.168.126.129
redis.port=6379
5.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
public Jedis jedis(){
//数据写死?????????
return new Jedis(host,port);
}
}
5.3编辑测试类
@SpringBootTest //需要依赖spring容器,从容器中动态的获取对象
public class TestRedis {
@Autowired
private Jedis jedis;
/**
* 完成Redis入门案例测试
* 报错说明:
* 1.检查Linux防火墙
* 2.检查Redis3项配置
* 3.重启redis.
*/
@Test
public void test01(){
//Jedis jedis = new Jedis("192.168.126.129",6379);
//1.向redis中保存数据
jedis.set("2004", "哈哈哈 今天下雨了 不负众望");
//2.从redis中获取数据
String value = jedis.get("2004");
System.out.println(value);
}
}
6.数据如何保存到Redis
6.1 业务说明
说明:由于redis中一般使用String数据类型保存业务数据.但是代码中java对象Redis没办法直接保存,所以需要中间的转化的过程.使用JSON方式进行数据中转.
List java对象 --------- JSON ------------ Redis中 使用String数据类型保存.
6.2ObjectMapper API介绍
package com.jt.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.pojo.ItemDesc;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class TestObjectMapper {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
public void test01(){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("测试JSON转化").setCreated(new Date())
.setUpdated(itemDesc.getCreated());
try {
//1.将java对象转化为JSON
String json = MAPPER.writeValueAsString(itemDesc);
System.out.println(json);
//2.将JSON转化为对象 利用反射机制实例化对象 利用get/set方法为对象赋值
ItemDesc itemDesc2 = MAPPER.readValue(json, ItemDesc.class);
System.out.println(itemDesc2.toString()); //只输出当前对象的数据
//3.将集合信息转化为JSON List
List<ItemDesc> list = new ArrayList<>();
list.add(itemDesc);
String listJSON = MAPPER.writeValueAsString(list);
System.out.println(listJSON);
//将json转化为List集合
List<ItemDesc> list2 = MAPPER.readValue(listJSON,list.getClass());
System.out.println(list2);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
6.3编辑工具API
说明::改工具API主要负责将用户参数转化为JSON,或者将JSON串转化为对象. 简化客户端调用
package com.jt.unit;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ObjectMapperUtil {
//1.创建工具API对象
private static final ObjectMapper MAPPER = new ObjectMapper();
//2.封装API 将对象转化为JSON
public static String toJSON(Object object){
if(object == null){
throw new RuntimeException("传入对象不能为null");
}
try {
String json = MAPPER.writeValueAsString(object);
return json;
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
/**
* 3.将JSON串转化为对象 用户传递什么类型,则返回什么对象
* user.class User对象
*
*/
public static <T> T toObject(String json,Class<T> target){
//1.校验参数是否有效
if(json == null || "".equals(json) || target == null){
//参数有误.
throw new RuntimeException("参数不能为null");
}
//2.执行业务处理
try {
T t = MAPPER.readValue(json, target);
return t;
} catch (JsonProcessingException e) {
//将报错信息通知其他人
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
6.4编辑工具API测试
//工具API测试
@Test
public void test02(){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("测试JSON转化").setCreated(new Date())
.setUpdated(itemDesc.getCreated());
String json = ObjectMapperUtil.toJSON(itemDesc);
ItemDesc itemDesc2 = ObjectMapperUtil.toObject(json, ItemDesc.class);
System.out.println(itemDesc2);
}