缓存机制
说明:使用缓存机制可以有效的降低用户访问物理设备的频次,快速从内存中获取数据返回给用户,同时,保证内存中的数据就是说数据库数据。
缓存要素:
缓存的运行环境应该在内存中,如果断电,数据将全部删除,持久化(磁盘)
实现缓存需要使用K–V的数据存储结构
缓存服务的开发使用的是C语言
缓存的数据都在内存中,如果一直储存数据则必然会导致内存溢出(内存优化:LRU算法、LFU算法)
Redis介绍
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
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)。
原子性说明: Redis的操作是单进程单线程操作,所以没有线程并发性的安全问题. 采用队列的方式一个一个操作.
Redis常见用法:
1.Redis可以当做缓存使用
2.Redis可以当做数据库使用:验证码
3.Redis可以消息中间件使用:银行转账等
Redis 服务器命令
启动命令:redis-server redis.conf
检索命令:ps -ef | grep redis
进入客户端:redis-cli -p 6379
关闭redis: kill -9 PID号 或 redis-cli -p 6379 shutdown
Redis入门案例
引入jar包
<!--spring整合redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
编辑测试API
package com.jt.test;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
public class TestRedis {
/**
* 1.测试redis程序链接是否正常
* 步骤:
* 1.实例化jedis工具API对象(host:port)
* 2.根据实例 操作redis 方法就是命令
* 关于链接不通的说明:
* 1.检查Linux防火墙
* 2.检查Redis配置文件修改项
* 2.1 IP绑定
* 2.2 保护模式
* 2.3 后台启动
* 3.检查redis启动方式 redis-server redis.conf
* 4.检查IP 端口 及redis是否启动...
* */
@Test
public void test01() {
String host = "192.168.126.129";
int port = 6379;
Jedis jedis = new Jedis(host, port);
jedis.set("2006", "sdf ");
System.out.println(jedis.get("2006"));
if(jedis.exists("2006")){
jedis.del("2006");
}else {
jedis.set("2006", "xxxx");
jedis.expire("2006", 100);
}
}
}
setex学习
/**
* 2.需求:
* 1.向redis中插入数据 k-v
* 2.为key设定超时时间 60秒后失效.
* 3.线程sleep 3秒
* 4.获取key的剩余的存活时间.
* 问题描述: 数据一定会被删除吗??????
* 问题说明: 如果使用redis 并且需要添加超时时间时 一般需要满足原子性要求.
* 原子性: 操作时要么成功 要么失败.但是必须同时完成.
*/
@Test
public void test02() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.setex("宝可梦", 60, "小火龙 妙蛙种子");
System.out.println(jedis.get("宝可梦"));
/* Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.set("宝可梦", "小火龙 妙蛙种子");
int a = 1/0; //可能会出异常
jedis.expire("宝可梦", 60);
Thread.sleep(3000);
System.out.println(jedis.ttl("宝可梦"));*/
}
setnx
/*3.需求:如果发现key已存在时 不修改数据;如果key不存在时才会修改数据*/
public void test03(){
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.setnx("aaaa", "测试nx的方法");
/*if(jedis.exists("aaa")){
System.out.println("key已经存在 不做修改");
}else {
jedis.set("aaa", "测试数据");
}*/
System.out.println(jedis.get("aaaa"));
}
set 超时时间原子性操作
/**
* 需求:
* 1.要求用户赋值时,如果数据存在则不赋值. setnx
* 2.要求在赋值操作时,必须设定超时的时间 并且要求满足原子性 setex
*/
@Test
public void test04() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
SetParams setParams = new SetParams();
setParams.nx().ex(20);
jedis.set("bbbb", "实现业务操作AAAA", setParams);
System.out.println(jedis.get("bbbb"));
}
list集合练习
@Test
public void testList() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.lpush("list", "1","2","3");
System.out.println(jedis.rpop("list"));
}
redis事务控制
@Test
public void testTx() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
//1.开启事务
Transaction transaction = jedis.multi();
try {
transaction.set("aa", "aa");
//提交事务
transaction.exec();
}catch (Exception e){
e.printStackTrace();
//回滚事务
transaction.discard();
}
}