目录
一、事务和锁机制
1.定义
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis事务的主要作用
串联多个命令防止别的命令插队。
2.Multi、Exec、discard
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,
直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队
⚪事务的不成功情况
- 有任何一个命令错误,最终都不会成功
- 如果执行中某个命令出了错误,只有它会报错,其它的正常执行
二、事务冲突
1.事务冲突的问题
2.悲观锁(Pessimistic Lock)
每次去拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁的机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁
3.乐观锁 (Optimistic Lock)
乐观锁,顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
4.WATCH key [key...]
在执行multi之前,先执行WATCH key1 [key2] ,可以监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其它命令所改动,那么事务将被打断
⭐示例:
5.redis事务的三个特性
①单独的隔离操作
事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中,不会被其它客户端发来的命令请求所打断
②没有隔离级别的概念
队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被原子的执行
③不保证原子性
事务中如果有一条命令执行失败,其它的命令仍会被执行,没有回滚
三、秒杀案例
⭐解决计数器和人员记录的事务操作
⚪基本功能实现
public class SecKill_redis {
public static void main(String[] args) {
Jedis jedis =new Jedis("192.168.XXX.XXX",6379);
System.out.println(jedis.ping());
jedis.close();
}
//秒杀过程
public static boolean doSecKill(String uid,String prodid) throws IOException {
//1.uid和prodid非空判断
if(uid == null || prodid == null) {
return false;
}
//2 连接redis
Jedis jedis = new Jedis("192.168.XXX.XXX",6379);
//3 拼接key
// 3.1 库存key
String kcKey = "sk:"+prodid+":qt";
// 3.2 秒杀成功用户key
String userKey = "sk:"+prodid+":user";
//4 获取库存,如果库存null,秒杀还没有开始
String kc = jedis.get(kcKey);
if(kc == null) {
System.out.println("秒杀还未开始,请耐心等待");
jedis.close();
return false;
}
// 5 判断用户是否重复秒杀操作
if(jedis.sismember(userKey, uid)) {
System.out.println("已经秒杀成功了,不能重复秒杀");
jedis.close();
return false;
}
//6 判断如果商品数量,库存数量小于1,秒杀结束
if(Integer.parseInt(kc)<=0) {
System.out.println("秒杀已经结束了");
jedis.close();
return false;
}
//7 秒杀过程
if(results == null || results.size()==0) {
System.out.println("秒杀失败~");
jedis.close();
return false;
}
//7.1 库存-1
//jedis.decr(kcKey);
//7.2 把秒杀成功用户添加清单里面
//jedis.sadd(userKey,uid);
System.out.println("秒杀成功!!!!!");
jedis.close();
return true;
}
}
进行一次点击后,库存数量减一
⚪使用ab模拟测试
①有网络
yum install httpd-tools
输入y完成安装
使用ab --help查看如何使用
Options are:
-n requests 本次总请求数
-c concurrency 并发数
-t timelimit 基础压测最大时间(秒),基于-n 50000的情况下最大测试时间,默认不显示。
-s timeout 请求超时时间(秒),默认30秒
-b windowsize 缓冲区大小(字节)
-B address Address to bind to when making outgoing connections
-p postfile POST请求文件,需要设置 -T
-u putfile PUT请求文件. 需要设置 -T
-T content-type POST/PUT请求header中的content-type值,默认是'text/plain'
-v verbosity 显示多少故障信息,1/2/3/4
-w 在html中显示结果
-i 使用head请求,默认是get
-x attributes 设置table属性
-y attributes 设置tr属性
-z attributes 设置th属性
-C attribute 添加cookie, 如:'Apache=1234',可重复
-H attribute 添加header, 如:'Accept-Encoding: gzip',追加常规header后面,可重复。
-A attribute 添加WWW认证信息, 格式'user:pwd'
-P attribute 添加基础身份认证信息,格式'user:pwd'
-X proxy:port 使用的代理服务端口
-V 显示版本
-k 使用http连接保持功能
-d 不显示时间百分比分布.
-S 不显示中位数和警告
-q 总请求数大于150时,不显示测试请求进度(Benchmarking localhost)。
-g filename 输出测试数据到指定文件.
-e filename 输出百分比CSV文件
-r 收到错误信息不退出
-h 显示帮助信息
-Z ciphersuite 指定SSL/TLS密码套件,参考openssl
-f protocol 指定SSL/TLS协议,如:(SSL3, TLS1, TLS1.1, TLS1.2 or ALL)
②没有网络
(1) 进入cd /run/media/root/CentOS 7 x86_64/Packages(路径跟centos6不同)
(2) 顺序安装
apr-1.4.8-3.el7.x86_64.rpm
apr-util-1.5.2-6.el7.x86_64.rpm
httpd-tools-2.4.6-67.el7.centos.x86_64.rpm
③通过ab进行测试
ab -n 1000 -c 100 -p ~/postfile -T application/x-www-form-urlencoded
http://192.168.XXX.XXX:8081/Seckill/doseckill
- -n 1000:请求的数量为1000
- -c 100:并发数量为100
- -p ~/postfile :postfile提交参数
(新建一个文档,名称为profile,内容为prodid=0101&)
- http://192.168.2.115:8081/Seckill/doseckill :地址