事务碰上锁好似那油锅里进了火

目录

前言

 场景

代码复现        

提出疑问

该怎么解决呢

        1.使用编程式事务

          2.将事务独立出一个方法


前言

         很多时候我们谈起事务都是如虎色变,一想起来都是脑袋懵懵的

  1. 事务的隔离级别及传播机制是什么
  2. Spring的事务底层实现原理了解吗
  3. 哪几种情况下事务会失效       

        锁相关的更是让人如临大敌

  1. 可重入锁ReetrantLock和synchronized的区别
  2. 分布式锁的实现
  3. 轻量级锁volatile关键字的实现
  4. 说一说synchronized的锁升级流程

        当然了,大家都很厉害,上面这些稍微有点难度,仍可一力当之

        但是当事务遇上了锁,难上加难,阁下该如何应对呢。

        没开玩笑。

        在日常开发中,事务必不可少,锁也一样,那事务碰上锁,我们该怎么办呢

       


 场景

        我举一个经典的下单场景

                1. 扣减库存

                2. 生成订单

        首先我们会考虑加事务,防止以上哪步数据库操作失败,回滚数据

        再次考虑并发问题,加锁,防止超卖


代码复现        

        我这里有个库存表product,一共10件商品

        

        模拟多线程调用,抢购这些商品,并创建订单。

        我们预期商品库存会变为0,并且生成10笔订单数据。

        我们根据直觉很容易写出如下代码,在方法上使用事务注解,用于异常回滚,使用锁(此处为了方便使用ReentrantLock,多服务一般都是使用分布式锁)用于并发控制。

        抢单逻辑如下:

        下面这段代码,方法上加了@Transactional(rollbackFor = Exception.class)

        方法的开启和结束也使用Lock加上了锁。

         给你几秒,好好想下,输出会是什么?

        订单表会生成多少条数据?

        “创建订单成功了”这个日志输出会打印多少次?

       没错,生成了20笔订单!!!!!

       订单表中一共20笔交易数据。

        怎么会这样!!!

        

          日志输出也是整整20次

        如果是实际商品售卖场景,结果就是我们只有10件库存,由于我们这段代码有问题,多生成了一倍订单,生成了20笔订单。

        呐,货发不发出去是小事,工作可是要没了呀,这,这以后,以后还怎么带薪摸鱼呢    

        我们把@Transactional(rollbackFor = Exception.class)这行代码先拿掉再重新看下执行结果。当然实际情况下肯定需要加事务的,此处只是为了对比排错。

        可以看到只生成了10笔订单数据

提出疑问

        1.为什么会发生超卖,是锁使用的有问题还是事务使用的有问题

        2.为什么是正正好好多卖了一倍

       


      

        先看第一个问题,为什么会超卖呢?

        先问下,上述代码锁释放的代码,在try代码块执行完之后,finally代码块里执行,那么事务什么时候提交的呢,是在 this.orderMapper.insert(order);这条插入语句之后吗?

        很明显不是的。

        本文示例中事务是在方法执行结束之后提交的,熟悉Spring事务的同学们肯定知道,声明式事务@Transactional注解是基于代理的方式进行的。

        打上断点分析下

        可以看到在TransactionAspectSupport类中,invokeWithinTransaction()方法先对实际@Transactional注解修饰的方法代理执行后,最后才提交的事务

        也就是说在锁释放之后,事务还没有提交,中间是有程序在执行的那么一小段时间的,在这段时间内,如果新的线程进来,查询到库存还是原值,这个时候就会发生超卖。

        虽然这个时间点很小,但是并发量稍微起来点,谁也不能保证什么都不会发生。

        正如我们实例中展示,很容易就发生了超卖

        我这儿有篇收藏已久的Spring事务秘籍,v我50可点击查看

        死磕Spring之AOP篇 - Spring事务详解 - 月圆吖 - 博客园 (cnblogs.com)


        第二个问题,为什么一直是正好是创建了20条数据订单呢

        其实不会一直是正好20条,只是大概率会20条。

        看下图,我们来分下下执行流程。

        假设这个时候库存还是10个

        1.线程1释放锁的时候,扣减库存之后,事务还没来的及提交

        2.这个时候线程2拿到了锁,由于线程1的事务还没有提交,线程2读到的库存数据还是10个,这个时候很大几率就会产生超卖了,注意哦,这里并不是一定会产生。

        3.关键点是线程3这个时候是参与不进来的,它很想进来,但法律不允许3p,不对。。是没有锁的权限,它只能等着线程2去释放锁。

        所以,超卖的情况下最多只能有两个线程,大概率是库存的两倍 20个。

        当然,我们可以尝试复现下创建订单数不是20个的场景。

        我们在每个线程加锁之前先让线程睡一会儿,目的是让之前的线程事务提交完毕再去获取锁,再去查询库存,这样就有几率避免超卖,要根据你系统运行环境的性能来调试。

        

        可以看到结果创建订单数就不会是20个了,而是13个

该怎么解决呢

        1.使用编程式事务

          为了方便,我这里使用  TransactionTemplate。

  

     

        2.将事务独立出一个方法

        注意哦,这里是会有坑的,不要定义成private方法,不要同类中直接调用。

        抽出doSell()方法,将事务操作独立出来,直接调用是不会生效为了演示方便,我这里当前类自己注入自己

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

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

相关文章

【探索C++】C++对C语言的扩展

(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮&#xff0…

JavaScript基础知识12——运算符:算数运算符,比较运算符

哈喽,大家好,我是雷工。 以下为JavaScript基础知识学习笔记。 一、算数运算符 1、算术运算符:即进行数学计算的符号。 2、有哪些算数运算符: :加法 -:减法 *:乘法 /:除法 %:取余(…

系统架构设计师-数据库系统(3)

目录 一、数据控制 1、安全性 2、完整性 3、并发控制 4、故障恢复 二、数据库设计概述 1、数据库设计关注的问题 2、数据库性能优化 3、规范化与反规范化 一、数据控制 1、安全性 2、完整性 (1)实体完整性约束:规定基本关系的主属性不能取空…

Python开发利器之VS Code

Python官方提供了一个Python集成开发环境(IDE): IDLE (Integrated Development and Learning Environment)。 它提供了一个图形用户界面,可以让开发者编写、调试和执行Python程序。IDLE包含Python解释器、代码编辑器、调试器和文件…

RK3568平台开发系列讲解(工具命令篇)ADB的安装

🚀返回专栏总目录 文章目录 一、ADB介绍二、Windows 下安装 adb 工具沉淀、分享、成长,让自己和他人都能有所收获!😄 一、ADB介绍 adb 全称 Android Debug Bridge,直译过来就是 Android 调试桥,它是一个通用的命令行工具。adb 做为 Android 设备与 PC 端连接的一个桥梁…

揭秘:Wasserstein GAN与梯度惩罚(WGAN-GP)

一、说明 什么是梯度惩罚?为什么它比渐变裁剪更好?如何实施梯度惩罚?在提起GAN对抗网络中,就不能避免Wasserstein距离的概念,本篇为系列读物,目的是揭示围绕Wasserstein-GAN建模的一些重要概念进行探讨。 图…

浅谈DBT的一些不足之处

DBT的好处是显而易见的,它支持连接多达41种数据库。而且不需要你写DDL语句,只要写select语句,DBT会自动帮你推断schema结构,将数据写入到数据库中: 但是使用了一段时间之后,发现DBT也存在着如下这些不足之处…

/usr/bin/ld: cannot find -lmysqlcllient

文章目录 1. question: /usr/bin/ld: cannot find -lmysqlcllient2. solution 1. question: /usr/bin/ld: cannot find -lmysqlcllient 2. solution 在 使用编译命令 -lmysqlclient时,如果提示这个信息。 先确认一下 有没有安装mysql-devel 执行如下命令 yum inst…

【Linux】Ubuntu美化主题【教程】

【Linux】Ubuntu美化主题【教程】 文章目录 【Linux】Ubuntu美化主题【教程】1. 安装优化工具Tweak2.下载自己喜欢的主题3. 下载自己喜欢的iconReference 1. 安装优化工具Tweak 首先安装优化工具Tweak sudo apt-get install gnome-tweak-tool安装完毕后在菜单中打开Tweak 然后…

**20.迭代器模式(Iterator)

意图:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 上下文:集合对象内部结构常常变化各异。对于这些集合对象,能否在不暴露其内部结构的同时,让外部Client透明地访问其中包含的元素…

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(三)

因为这个版本的若依plus不支持本地文件上传&#xff0c;所以需要增加这些本地上传文件的后端代码 和前端代码修改。 1、后端部分 先配置跳过测试吧&#xff0c;平时编译也不需要这个 <!--添加配置跳过测试--><plugin><groupId>org.apache.maven.plugins<…

Python常用库(六):科学计算库-Numpy[上篇]:创建、访问、赋值

1.Numpy 1.1 介绍 NumPy是Python中非常流行且重要的科学计算库&#xff0c;提供了一个强大的多维数组对象(ndarray)和许多数学操作&#xff0c;包括矩阵运算、线性代数、微积分等等。 numpy是Python中一个非常有用的工具&#xff0c;特别是在需要进行数值计算、线性代数计算、…

淘宝分布式文件存储系统( 三 ) -TFS

淘宝分布式文件存储系统( 三 ) ->>TFS 目录 : 文件重新映射的接口介绍文件映射 mmap_file.cpp的实现进行测试 文件重新映射 (增加 或者 减少 文件映射区域的大小) mremap() 函数的原型如下 #include <sys/mman.h> void *mremap( void * old_address , size_…

阿里测开面试大全(一)附答案完整版

万字长文&#xff0c;建议收藏 1 什么是POM&#xff0c;为什么要使用它&#xff1f; POM是Page Object Model的简称&#xff0c;它是一种设计思想&#xff0c;而不是框架。大概的意思是&#xff0c;把一个一个页面&#xff0c;当做一个对象&#xff0c;页面的元素和元素之间操…

JS Ajax 封装

ajax 封装 一、 什么是Ajax&#xff1f;二、 Ajax的优缺点&#xff1f;2.1 优点2.2 缺点 三、 Ajax的使用3.1 状态码3.2 xhr的基本使用3.3 ajax原生封装&#xff1a;3.3.1 触发GET请求&#xff1a;3.3.2 调用POST请求&#xff1a; 四、Ajax的约束 一、 什么是Ajax&#xff1f; …

【新版】系统架构设计师 - 案例分析 - 数据库设计

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 数据库设计数据库基础数据库设计概述E-R模型概念结构设计逻辑结构设计规范化&#xff08;范式&#xff09;反规范化技术数据库事务并发控制索引视图物化视图存储过程触发器数据库性能优…

【Spring Cloud系列】Feign详解与实战

Feign详解与实战 文章目录 Feign详解与实战一、概述二、什么是Feign三、Feign特性四、Feign简单使用3.1 Feign使用步骤3.2 Feign具体使用1. 引入依赖2. 启动类上添加注解3.编写FeignClient接口 五、使用Feign发起http请求5.1 Maven导入Feign配置&#xff0c;并集成Jackson5.2 F…

基于matlab实现的光折射反射(不同界面)程序

完整程序: %平面电磁波在不同介质界面上入射、反射、折射仿真 %ReadMe!!!在下述说明的用户输入区内输入入射角和两介质折射率&#xff0c; %输出反射折射示意图与反射折射系数随入射角变化的曲线 %—————————————————————————————————————…

百度SEO优化TDK介绍(分析下降原因并总结百度优化SEO策略)

TDK是SEO优化中很重要的部分&#xff0c;包括标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keyword&#xff09;&#xff0c;为百度提供网页内容信息。其中标题是最重要的&#xff0c;应尽量突出关键词&#xff0c;同时描述…

9.20 QT作业

widget.h #include <QPainter> //画家 #include <QTimerEvent> #include <QTime> #include<QTimer> //定时器类QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widge…