缓存机制
说明:使用缓存可以有效的降低用户访问物理设备的频次,快速从内存中后去数据,之后返回给用户需要保证内存中的数据就是数据库数据。
1.缓存的运行环境应该在内存中(快)。
2.使用C语言开发缓存。
3.缓存的数据结构【K——V结构,一般采用String类型多,hey必须唯一,v:Json格式】。
4.内存环境断电即擦除,所以应该将内存数据持久化(执行写盘操作)。
5.如果没有维护内存的大小,则容易导致内存溢出,所以采用LRU算法优化!
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的安装
1.解压Redis安装包
[root@localhost src]# tar -zxvf redis-5.0.4.tar.gz
2.安装Redis
说明:在Redis的根目录中执行命令
命令:
1."make"
2.make install
修改Redis的配置文件
Redis服务器命令
1.启动命令: redis-server redis.conf
2.检索命令: ps -ef | grep redis
3.进入客户端: redis-cli -p 6379(如果默认端口是6379则这里的端口号可以省略)
4.关闭redis: kill -9 PID号 | redis-cli -p 6379 shutdown
Redis入门案例
引入jar包文件
redis.clients
jedis
org.springframework.data
spring-data-redis
编辑测试API
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", "好好学习天天向上");
System.out.println(jedis.get("2006"));
//练习是否存在key
if(jedis.exists("2006")){
jedis.del("2006");
}else{
jedis.set("2006","hdsjiahjds");
jedis.expire("2006", 100);
}
}
setex的使用
/**
* 需求:
* 1.向redis中插入数据
* 2.为key设定超时时间。,60秒后失效
* 3.线程sleep 3秒
* 4.获取key的剩余的存活时间
*
*/// 如果用下面这种方法的话会导致出现异常的话下面的代码不执行,所以要满足原子性要求
@Test
public void test02() throws InterruptedException {
Jedis jedis=new Jedis("192.168.126.129",6379);
jedis.set("红楼梦", "贾宝玲");
jedis.expire("红楼梦", 60);
Thread.sleep(3000);
System.out.println(jedis.ttl("红楼梦"));
}
/*如果用redis并且需要添加超时时间时,一般需要满足原子性要求
* 原子性: 操作时要么成功要么失败,但是必须同时完成
* 用setex完成redis的添加,setex保证数据的原子性操作
* */
@Test
public void test03() throws InterruptedException {
Jedis jedis=new Jedis("192.168.126.129",6379);
jedis.setex("红楼梦",60, "林黛玉");
System.out.println(jedis.get("红楼梦"));
}
setnx的使用
/**
* 判断数据是否已经存在,如果已经存在则不修改,如果不存在则添加
*
* 之前用if判断语句来判断数据是否已经存在,
* 在这里用setnx判断数据是否已经存在
* */
@Test
public void test04() throws InterruptedException {
Jedis jedis=new Jedis("192.168.126.129",6379);
/*if(jedis.exists("aa")){
System.out.println("key已经存在,不修改");
}else{ jedis.set("aa", "测试数据");
}*/ jedis.setnx("aaa", "数据是否存在");
System.out.println(jedis.get("aaa"));
}
set超时时间原子性操作
/**
* 需求:
* 1.要求用户赋值时,如果数据存在则不赋值。 setnx
* 2.要求在赋值操作时,必须设定超时的时间,并且要求满足原子性 setex
* * 如果同时要满足这两个要求的话则不能用setnx和setex。因为这两个方法在单独
* 执行时是可以的,但是放在一块一起执行的话则会出错。
* 所以这里要用set方法,里面的params则是表示设置一个set对象。
* SetParams中的参数:
* nx:当数据不存在的时候才会赋值
* xx:当数据存在的时候才会赋值
* ex:表示失效的时间,单位是秒
* px:也表示失效的时间,单位是毫秒
*/
@Test
public void test05(){
Jedis jedis=new Jedis("192.168.126.129",6379);
SetParams setParams=new SetParams();
setParams.nx().ex(60);//加锁的操作
jedis.set("bbb", "实现业务操作ccc", setParams);
System.out.println(jedis.get("bbb")+jedis.ttl("bbb"));
jedis.del("bbb");//解锁的操作
}
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();
}
}
分布式锁机制简单说明
说明:秒杀业务逻辑
如果1元抢购一部价值6988的手机可能会造成多个用户都抢购成功并且支付成功。
问题:
1.tomcat服务器有多台
2.数据库只有一份
3.必然会出现高并发的现象。
如何实现抢购?
常规锁操作
超卖的原因
同步锁的问题
说明:同步锁只能解决tomcat内部的问题,不能解决对个tomcat并发问题。
分布式锁机制
思想:
1.锁应该使用第三方操作,应该公用!
2.原则:如果锁正在被使用时,其他的用户不能操作。
3.策略:用户向redis保存一个key,如果redis中有key表示有人正在使用这把锁,其他用户不允许操作。如果redis中没有key,则表示可以使用这把锁。
4.风险:如何解决死锁问题?-->设定超时时间。