Redis缓存
1.1 Redis简介
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
Redis 是一个高性能的key-value数据库。Redis支持主从同步。它可以用作数据库、缓存和消息中间件。
nosql:非关系型数据库:Redis,mongdb,HBASE;
消息中间件:主要的作用是为了实现数据的平滑过渡,让程序调用更加流畅(就像润滑剂)
1.2 为什么要使用缓存
使用缓存可以有效的降低用户访问物理设备的频次,有效的减少并发的压力,真正有效的保护真实的服务器.
1.3 缓存应该如何设计
- 缓存应该使用什么样的数据结构 ?(Key-Value数据结构,key必须是唯一的)
- 如何需要缓存进行快速的读取,首先开发语言如何选择?(C语言,在软件的运行环境在内存中)
- 如何防止内存数据丢失! 缺点: 断电即消除 内存数据的持久化操作(内存数据保存到磁盘中)
- 缓存的空间大小如何维护. 不能一直存,有时也会删除数据 如何操作? 内存优化算法: LRU算法/LFU算法
- .缓存使用如何防止宕机带来的影响? (HA)高可用 部署redis集群.
2.在Linux上操作Redis
2.1 上传Redis安装包并解压
命令: tar -zxvf
安装说明:在redis的根目录中执行
1、安装gcc环境
由于redis是由C语言编写的,它的运行需要C环境,因此我们需要先安装gcc。安装命令如下:
[root@localhost mnt]# yum install gcc-c++
命令1: make
命令2: make install
2.2 修改配置文件
命令: vim redis.conf
1).注释IP绑定
2).修改保护模式 默认为yes,改为no
3).开启后台启动
2. 3 关于redis服务器命令
- 启动redis:
命令:redis-server redis.conf
- 进入客户端
命令:redis-cli -p 6379
,如果是默认端口号6379 命令可以简写:redis-cli
- 关闭redis
命令:redis-cli -p 6379 shutdown
可简写为 :redis-cli shutdown
- 查询redis进程
3. Redis 入门
3.1 导入jar包
<!--spring整合redis Redis的底层jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- spring负责连接Redis的连接包 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
3.2 创建redis测试类
注意:在测试时,常见的错误说明:
- 检查redis配置文件redis.conf,是否修改上述描述的3处
- 检查redis是否已启动, redis-server redis.conf
- 检查Linux的防火墙是否关闭
//setnx:只有当数据不存在的时候赋值
@Test
public void testRedis01() {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.flushAll();//清空所有数据
jedis.setnx("a", "测试setnx的方法1");
jedis.setnx("a", "测试setnx的方法2");
System.out.println(jedis.get("a"));//测试setnx的方法1
}
//setex 保证赋值操作和添加超时时间的操作的原子性
@Test
public void testRedis02() throws InterruptedException {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.flushAll();
jedis.set("a", "aaa");//如果程序报错,则超时方法将不会执行,修改数据将永不执行
//假如在此处突然意外程序错误,以下添加时间就不会有效
jedis.expire("a", 20);//添加超时,不是原子性操作
Thread.sleep(20000);
System.out.println("剩下存活时间"+jedis.ttl("a"));
//方法2.可以实现原子性操作
jedis.setex("b", 20, "原子性操作");
System.out.println(jedis.get("b")+"剩下存活时间"+jedis.ttl("b"));
}
/**
* 要求:
* 1.只有数据不存在时运行修改
* 2.要求实现添加超时时间,并且是原子性操作
* SetParams 参数说明
* public class SetParams extends Params {
private static final String XX = "xx";
private static final String NX = "nx";
private static final String PX = "px";
private static final String EX = "ex";
....
}
* 1.NX 只有key不存在时才能修改
* 2.XX 只有key存在时才能修改
* 3.PX 添加的时间单位为毫秒
* 4.EX 添加的时间单位为秒
*/
@Test
public void testRedis05(){
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.flushAll();
SetParams params = new SetParams();
params.xx().ex(20);
jedis.set("aa", "赋值测试", params);
jedis.set("aa", "bb赋值测试", params);
System.out.println(jedis.get("aa")+jedis.ttl("aa"));//null -2
}
/**
* 存储一类数据时,用Hash
*/
@Test
public void testHashRedis(){
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.flushAll();
jedis.hset("user", "name","tomct");
jedis.hset("user", "id","100");
System.out.println(jedis.hgetAll("user"));//user不是一个对象,是一个map集合
}
@Test
public void testList(){
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.flushAll();
jedis.lpush("list", "1","2","3","4","5");//从队列的左边入队一个或多个元素
System.out.println(jedis.rpop("list"));//当队列使用,先进先出,1
System.out.println(jedis.lpop("list"));//当栈使用,先进后出,5
}
4. Spring 整合 Redis
说明:将jedis对象交给spring容器管理,之后哪里需要就直接注入即可
步骤:
- 编辑redis.properties文件,指定redis节点 IP,port
- 由于redis比较重要,很多业务系统都需要调用,所以将redis整合写入common
- 通过配置类(配置文件)形式整合redis.
4.1 编辑redis.properties文件
4.2 编辑配置类
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
//将返回值的结果交给spring容器进行管理,如果以后想要使用该对象则可以直接注入
@Bean
public Jedis jedis() {
return new Jedis(host,port);
}
}
4.3 封装ObjectMpaperUtil
说明:该API主要负责将对象转化为json字符串或将json串转化成对象
public class ObjectMapperUtil {
//json与对象的转化,优化异常处理
private static final ObjectMapper MAPPER = new ObjectMapper();
//1.将对象转化成JSON格式
public static String toJson(Object obj) {
if(StringUtils.isEmpty(obj))
throw new IllegalArgumentException("对象不能为空!");
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException("转化异常");
}
}
//<T> 定义了一个泛型对象 代表任意类型
public static <T> T toObject(String josn,Class<T> oClass) {
if(StringUtils.isEmpty(josn)||oClass==null)
throw new IllegalArgumentException("参数不能为空");
try {
return MAPPER.readValue(josn, oClass);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException("转化异常");
}
}
}