Redis事务+秒杀案例

        Redis事务是一个单独的隔离操作,是指将多条命令放在一个命令队列当中,按顺序执行,保证多个命令在同一个事务中执行而不受其他客户端的影响。

        通俗来说就是:串联多个命令防止别的命令插队。

1.Multi、Exec、discard

        在输入Multi命令后,输入的命令都会依次进入命令队列中,这一过程也叫组队,直到输入Exec后,Redis会将命令队列中的命令依次执行。如下示例:

        而且在组队的过程中可以通过discard来退出输入,结束这个事务。如下示例:  

 

2.事务错误的处理

2.1组队的过程中报错

        如果组队的过程中添加命令时出现了错误,那么输入exec执行时队列中所有的命令都不会执行。  

2.2执行过程中报错

redis的事务中不会保证原子性,其中第二条命令有误,并不会影响命令1和命令3的执行。

3.Redis怎么解决事务冲突问题(watch)

        比如高并发下多个请求同时操作同一个账户,那么账户余额就可能出现问题,正常情况可以采用悲观锁或者乐观锁来解决。其中悲观锁实现就是给账户余额加锁,同一时间只能由一个事务来操作。乐观锁实现就是通过版本号来控制。但是乐观锁适用于读多写少的场景,而Redis就是利用乐观锁这种CAS机制来解决事务冲突问题的。

3.1对watch我的理解

        有客户端A和B,客户端A执行了watch key,就代表着A监视着此key,A会保存一份key的当前版本号,如果(无论什么地方)修改了此key的值,那么key的版本号就会发生变更。

        而判断比较key的版本号,这个环节只和事务有关系,只会在multi开启事务后,然后exec执行命令时才会生效。比如多个事务在输入multi命令之前,可以先执行watch key1 ....,用来监视一个或多个key,如果事务A在exec执行时发现事务A监视的key的版本已经被改动,那么这个事务A的命令队列就会被打断,命令全部不会执行,当操作被打断时,会返回空值nil

4.Redis事务的三大特性

  • 单独的隔离操作。

  • 没有隔离级别的概念。

  • 不保证原子性,出现错误继续向下执行。

5.秒杀案例

我们通过ab工具实现了并发模拟秒杀,结果出现了库存超卖和redis连接超时的问题。以下分析出现原因:

  • 超卖:在高并发请求下,多个请求同时开始查询到的是有库存的,然后就一窝蜂的去减库存,就会导致超卖。

  • 连接超时:因为redis是单线程操作内存,如果一瞬间请求过多,一直排在后面的请求就可能会产生连接超时。

5.1解决超卖问题

如果只需解决超卖问题其实也不难,我们可以使用watch来监视库存,从而使用乐观锁解决超卖的问题。

示例代码(qtkey表示的是库存的键,userkey表示存放用户id的key):

//增加乐观锁,监视库存
jedis.watch(qtkey);
//判断库存
String qtkeystr = jedis.get(qtkey);
if(qtkeystr==null || "".equals(qtkeystr.trim())) {System.out.println("未初始化库存");jedis.close();return false ;
}
int qt = Integer.parseInt(qtkeystr);
if(qt<=0) {System.err.println("已经秒光");jedis.close();return false;
}
//增加事务
Transaction multi = jedis.multi();
//减少库存
multi.decr(qtkey);
//添加用户信息
multi.sadd(usrkey, uid);
//执行事务
List<Object> list = multi.exec();
//判断事务提交是否失败
if(list==null || list.size()==0) {System.out.println("秒杀失败");jedis.close();return false;
}
System.err.println("秒杀成功");
jedis.close();

5.2解决连接超时的问题

        问题就是每个请求都要自己等待去建立和关闭连接,我们使用连接池来解决即可,连接池还能节省每次连接redis服务带来的消耗,能反复利用。

5.3库存遗留怎么解决

        我们使用乐观锁能够很好的解决超卖的问题,但是无法解决库存遗留的问题,比如库存余额为10,此时有50个请求同时过来,但是由于CAS导致很多的请求都失败了,导致先点的没抢到,后来的反而抢到了。虽然请求很多,但最终都可能导致还有库存遗留,这样就不太好。

        而且redis不支持悲观锁,所以用LUA脚本来解决。

        LUA是一个脚本语言,LUA脚本有一定的原子性不会被其他命令插队。我们将多步操作,写为一个脚本,一次性的交给redis执行。

        因为redis其单线程的特性,同一时间只能将一个LUA脚本彻彻底底的执行完后,才能执行下一个LUA脚本,所以LUA能同时解决超卖的问题和库存遗留的问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/200699.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx配置-超详细

背景 安装nginx之后&#xff0c;会自动生成很多的文件&#xff0c;但是nginx.conf这个文件是我们的核心&#xff0c;如何去正确的修改和优化它是nginx的核心。在配置之前&#xff0c;需要看懂它的配置。鉴于经常需要配置&#xff0c;再次记录一下 一、nginx的默认配置 #user …

【C++】类和对象(6)--运算符重载

目录 一 概念 二 运算符重载的实现 三 关于时间的所有运算符重载 四 默认赋值运算符 五 const取地址操作符重载 一 概念 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数…

【UE】线框材质

一、方式1 新建一个材质&#xff0c;混合模式设置为“已遮罩”&#xff0c;勾选“双面” 勾选“线框” 然后可以随便给一个自发光颜色&#xff0c;这样最基本的线框材质就完成了 二、方式2 新建一个材质&#xff0c;混合模式设置为“已遮罩”&#xff0c;勾选“双面”&#x…

计算机算法分析与设计(24)---分支限界章节复习

文章目录 一、分支界限法介绍二、旅行商问题应用三、装载问题应用3.1 问题介绍与分析3.2 例题 四、0-1背包问题应用4.1 问题介绍与分析4.2 例题 一、分支界限法介绍 二、旅行商问题应用 三、装载问题应用 3.1 问题介绍与分析 3.2 例题 四、0-1背包问题应用 4.1 问题介绍与分析…

读像火箭科学家一样思考笔记05_思想实验

1. 思想实验室 1.1. 思想实验至少可以追溯到古希腊时期 1.1.1. 从那时起&#xff0c;它们就跨越各个学科&#xff0c;在哲学、物理学、生物学、经济学等领域取得重大突破 1.1.2. 它们为火箭提供动力&#xff0c;推翻政府&#xff0c;发展进化生物学&#xff0c;解开宇宙的奥…

2023.11.19使用flask制作一个文件夹生成器

2023.11.19使用flask制作一个文件夹生成器 实现功能&#xff1a; &#xff08;1&#xff09;在指定路径上建立文件夹 &#xff08;2&#xff09;返回文件夹的路径和建立成功与否的提示 main.py import os from flask import Flask, request, jsonify, render_templateapp F…

CNP实现应用CD部署

上一篇整体介绍了cnp的功能&#xff0c;这篇重点介绍下CNP产品应用开发的功能。 简介 CNP的应用开发&#xff0c;主要是指的应用CD部署的配置管理。 应用列表&#xff0c;用来创建一个应用&#xff0c;一般与项目对应&#xff0c;也可以多个应用对应到一个项目。具体很灵活。…

Netty源码学习4——服务端是处理新连接的netty的reactor模式

零丶引入 在前面的源码学习中&#xff0c;梳理了服务端的启动&#xff0c;以及NioEventLoop事件循环的工作流程&#xff0c;并了解了Netty处理网络io重要的Channel &#xff0c;ChannelHandler&#xff0c;ChannelPipeline。 这一篇将学习服务端是如何构建新的连接。 一丶网络包…

【STM32】W25Q64 SPI(串行外设接口)

一、SPI通信 0.IIC与SPI的优缺点 https://blog.csdn.net/weixin_44575952/article/details/124182011 1.SPI介绍 同步&#xff08;有时钟线&#xff09;&#xff0c;高速&#xff0c;全双工&#xff08;数据发送和数据接收各占一条线&#xff09; 1&#xff09;SCK:时钟线--&…

【数据结构】栈和队列的模拟实现

前言&#xff1a;前面我们学习了单链表并且模拟了它的实现&#xff0c;今天我们来进一步学习&#xff0c;来学习栈和队列吧&#xff01;一起加油各位&#xff0c;后面的路只会越来越难走需要我们一步一个脚印&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x…

Golang基础-面向对象篇

文章目录 struct结构体类的表示与封装类的继承多态的基本要素与实现interface空接口反射变量的内置pairreflect包解析Struct TagStruct Tag在json中的应用 struct结构体 在Go语言中&#xff0c;可以使用type 关键字来创建自定义类型&#xff0c;这对于提高代码的可读性和可维护…

win11,引导项管理

1&#xff0c;打开cmd,输入msconfig 2,进入引导选项卡 3&#xff0c;删除不需要的引导项

ETL-使用kettle批量复制sqlserver数据到mysql数据库

文章标题 1、安装sqlserver数据库2、下载kettle3、业务分析4、详细流程&#xff08;1&#xff09;转换1&#xff1a;获取sqlserver所有表格名字&#xff0c;将记录复制到结果&#xff08;2&#xff09;转换2&#xff1a;从结果设置变量&#xff08;3&#xff09;转换3&#xff…

【Linux】:共享内存

共享内存 一.原理二.创建共享内存1.shmget2.写一个共享内存代码 三.进行通信1.各种接口2.各接口使用代码3.一次简单的通信四.共享内存的特点 一.原理 直接原理 共享内存顾名思义就是共同使用的一块空间。 很明显操作系统需要对这块内存进行管理&#xff0c;那么就避免不了先描…

Servlet执行流程Servlet 生命周期

Servlet 生命周期 对象的生命周期指一个对象从被创建到被销毁的整个过程 import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; WebServlet(urlPatterns "/demo",loadOnStartup 10) public class ServletDemo imple…

华为ac+fit漫游配置案例

Ap漫游配置: 其它配置上面一样,ap管理dhcp和业务dhcp全在汇聚交换机 R1: interface GigabitEthernet0/0/0 ip address 11.1.1.1 255.255.255.0 ip route-static 12.2.2.0 255.255.255.0 11.1.1.2 ip route-static 192.168.0.0 255.255.0.0 11.1.1.2 lsw1: vlan batch 100 200…

存储日志数据并满足安全要求

日志数据是包含有关网络中发生的事件的记录的重要信息&#xff0c;日志数据对于监控网络和了解网络活动、用户操作及其动机至关重要。 由于网络中的每个设备都会生成日志&#xff0c;因此收集的数据量巨大&#xff0c;管理和存储所有这些数据成为一项挑战&#xff0c;日志归档…

Windows系统如何安装与使用TortoiseSVN客户端,并实现在公网访问本地SVN服务器

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

2023年以就业为目的学习Java还有必要吗?

文章目录 1活力四射的 Java2从零开始学会 Java3talk is cheap, show me the code4结语写作末尾 现在学 Java 找工作还有优势吗&#xff1f; 在某乎上可以看到大家对此问题的热议&#xff1a;“2023年以就业为目的学习Java还有必要吗&#xff1f;” 。有人说市场饱和&#xff0c…

关于lenra你需要了解的

monorepo&#xff1a;项目代码管理方式&#xff0c;单个仓库中管理多个项目是一种设计思想 lenra&#xff1a;是一种工具&#xff0c;对于使用npm和git管理多软件包代码仓库的工作流程进行优化 使用这些工具的优点&#xff1a; 公共依赖只要安装一次&#xff0c;Monorepo 中…