最近在整理关支付安全的内容,其中就是涉及到了一个在支付过程中的条件竞争问题。以下都是基于mysql的与php的架构来描述该问题,大佬勿喷。

0x01. 条件竞争

什么是条件竞争:

竞争条件 发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中。【Wikipedia-computer_science】

一个简单的购买的业务:

后台代码实现如下:

以上是一个购买商品的流程,看似并没有什么问题。

如果每次请求都是一个单线程的请求是没有什么问题的,但是如果采用多线程的并发请求就会出现问题。

因为每次的购买流程都是需要一定的时间去按照购买的流程执行,如果我们在第一次购买的流程3还没有结束时,就再去执行这一遍流程时,那么在第流程2时查询用户的余额就还是初始的余额,这是因为第一次购买的流程3还没有结束,没有结束也就意味着余额没有扣除,所以金额就是初始的值。

在上面的百年青花瓷购买的案例中,如果我们只有1000块钱,但是我们在多线程的情况下去购买青花瓷的时候就可能购买到10件以上的数目。

0x02. 实际测试

在数据库查看用户数据

2.打开购买页面

打开burp拦截购买商品的数据包,点击购买。

设置intruder发送50个数据包,线程调到25后发包

并发请求后查看购买页面,已拥有17件,余额成了-700。

我们调出mysql的查询日志。

从日志中可以看到我们的请求是并发的执行的,在一次查询还没有结束时就进行了下一次的查询,所以这也很容易产生两次查询的余额是相同的。

所以当我只剩100块的只能购买一件商品的时候,但是有可能两次查询余额都100,是符合购买流程的操作的,后面也会对余额100进行两次扣除操作,所以最后余额变成了负数,购买的数量也大于10。

0x03. Solve the problem

mysql事务

在网上看到一篇关于mysql与php的条件竞争的分析中的解决方案是这样的:

这种解决的方案的意思是给mysql查询进行一个事务的处理,在mysql的查询前添加一个BEGIN,开始一个事务,在结束时添加一个COMMIT提交一个事务,完成一个查询操作。

本地测试一下

设置好线程再次并发购买一次,结果发现还是失败了。并没有解决条件竞争带来的问题,所以解决方案是不行的。

什么是mysql的事务

事务是一组原子性sql查询语句,被当作一个工作单元。若mysql对改事务单元内的所有sql语句都正常的执行完,则事务操作视为成功,所有的sql语句才对数据生效,若sql中任意不能执行或出错则事务操作失败,所有对数据的操作则无效(通过回滚恢复数据)。

通过上面一句话差不多就知道了原因,只有在查询语句不能执行或出错则事务操作失败, 所以我们添加事务并不能解决mysql竞争的问题,因为我们的查询是不会错误的,既然不会出错也就会照样执行并发的请求。

0x04. mysql锁

悲观锁

悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作对某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。 悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

当我们查询的数据随时可能会被其他操作修改时,我们对这个数据进添加一个悲观锁,如果想再次对这个数据进行操作时,只有这条查询的操作结束后释放这个悲观锁,其他查询才可以对这条数据进行操作,如果锁定没有结束时,其他查询会一直进行一个等待的状态。

mysql 悲观锁的实现

select * from goods where id = 1 for update;

for update仅适用于InnoDB引擎,且必须在事务块(BEGIN/COMMIT)中才能生效。在进行事务操作时,通过“for update”语句,MySQL会对查询结果集中每行数据都添加排他锁,其他线程对该记录的更新与删除操作都会阻塞。排他锁包含行锁、表锁。

使用悲观锁解决上述并发问题:

并发测试:

经过多次测试后发现商品购买正常。没有出现条件竞争的问题

我们这边来看下后端mysql查询的日志

我们吧mysql的查询分成了11组

前七组都没条件竞争的问题,所有操作都是有序执行的,但是在第八组的时候开始出现问题

在第八条数据查询的事务还没有结束时就开始查询第九条的数据了

但是由于我们使用了for update(悲观锁),对select语句进行锁定,所以在执行到第九条的时候发现第八条的事务还没有结束,所以他就只能等待第八条的更新完库存之后执行commit(提交事务)操作,第八条查询的锁才会进行释放,然后第九条查询才能获取到用户的余额进行下一步操作。所以通过悲观锁解决了条件竞争带来的问题。

但是悲观锁的弊端在每次查询都会对数据进行锁定,在高并发的请请求下会变得很慢。所以高并发的请求不建议使用悲观锁。

乐观锁

时间有限,下次再讲

在这个寒冷的时节里

因为有你的关注

而变得温暖

mysql锁争用_关于MYSQL条件竞争与锁的问题相关推荐

  1. MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结

    MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结 一.VARCHAR存储和行长度限制 1.VARCHAR(N)中,N指的是字符的长度,VARCHAR类型最大支持65535,指的是 ...

  2. mysql 锁设置密码_[转载]mysql锁小结

    Record Lock 总是会去锁住索引记录,如果innodb存储引擎表在建立的时候没有设置任何一个索引,而且查询的时候没有使用到索引,那么这时就会导致表锁. Next-Key Lock是结合了Gap ...

  3. mysql 高并发写入锁表_使用mysql中的锁解决高并发问题

    阿里云产品通用代金券,最高可领1888分享一波阿里云红包. 阿里云的购买入口 为什么要加锁 多核计算机的出现,计算机实现真正并行计算,可以在同一时刻,执行多个任务.在多线程编程中,因为线程执行顺序不可 ...

  4. 1. 请简述mysql数据库的锁机制_【MySQL入门】之MySQL数据库的锁机制(二)

    上篇文章主要聊了全局锁和表锁,并详细分析MDL锁的作用以及可能带来的问题.今天我们主要来聊一聊Innodb存储引擎的行锁.MySQL的行锁是在引擎层由引擎自己实现的,并不是所有的引擎都支持行锁,MyI ...

  5. mySQL无锁队列_使用 MySQL 实现无锁任务队列(using MySQL as a job queue)

    目录目录 场景 关键问题 有问题的解决方案 方案1 - 锁表 方案2 - SELECT FOR UPDATE 无锁任务队列 关键问题及解决方案 References 场景N 个生产者往 db 里面插入 ...

  6. mysql悲观群_谈谈mysql的悲观和乐观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.之前有写过一篇文章关于并发的处理思路和解决方案,这里我单独将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍一 ...

  7. mysql排他锁 升级_将共享升级到排他锁时避免MySQL死锁

    我使用MySQL 5.5.我注意到在并发情况下发生了特殊的僵局,我不认为这种僵局应该发生. 重现这样,使用两个同时运行的mysql客户端会话: mysql session 1: create tabl ...

  8. mysql数据库管理维护_深入浅出MySQL 数据库开发 优化与管理维护 第3版

    资料目录: 第 一部分 基础篇 第 1章 MySQL的安装与配置 2 1.1 MySQL的下载 2 1.1.1 在Windows平台下下载MySQL 3 1.1.2 在Linux平台下下载MySQL ...

  9. 高性能mysql总结笔记_高性能MySQL第三本笔记总结(上)

    无论何时,只要有多个查询需要在同一个时刻修改数据时,就会有并发问题.MySql主要在服务器层与存储引擎层进行并发控制. 假设数据库中国一张邮箱表,每个邮件都是一条记录.如果某个客户正在读取邮箱,同时其 ...

最新文章

  1. php中的mysql模块
  2. Real6410的NBL1.LSB和NBL2编译下载不能启动的问题
  3. 体验决定销量,真假4K争论仅仅是忽悠人而已
  4. android 环境配置和安装, Android系统包说明,基本控件,常用代码,ADB 命令行,APK文件确解,小技艺,...
  5. 数据库常用增删改查记录等语句
  6. Linux:分享50个实用的基础命令,欢迎收藏!
  7. 【剑指offer - C++/Java】4、重建二叉树
  8. java自学 day8
  9. c++ break跳出几个循环_必须知道的C语言知识细节:break、continue语句区别
  10. JavaWeb:JSON对象和Java对象的相互转换
  11. KnockOutlook:针对Outlook的红队安全研究工具
  12. 深入理解java虚拟机 - 垃圾回收机制(GC)
  13. 三星s10刷linux,三星S10/S10+刷入TWRP_Recovery最新版教程
  14. 公链洗牌进行时 |链捕手
  15. 利用Python爬取小说(附源码)
  16. python 公主连接_ss
  17. QT案例 使用QGraphicsView和命令模式设计完成流程图功能软件,参考QT官方流程图案例【diagramscene】
  18. JQ如何获取原生的event对象
  19. ffmpeg 缩放算法_抖音快手短视频分屏怎么做?ffmpeg scale过滤器了解下
  20. docker: no matching manifest for windows/amd64 10.0.17134 in the manifest list entries.

热门文章

  1. art-template-loader:template
  2. iOS 删除、重新排序xcdatamodel
  3. 合理提升WEB前端性能
  4. 什么时候加上android.intent.category.DEFAULT和LAUNCHER
  5. [编写高质量代码:改善java程序的151个建议]建议31-在接口中不要存在实现代码...
  6. Eclipse如何提高开发效率(转)
  7. 关于JS在IE和FF下attachEvent,addEventListener学习笔记
  8. 计算机二级html真题,计算机二级《Web程序设计》试题及答案
  9. php ajax成功失败,php – 让$.ajax失败
  10. python中paste函数的作用_PIL使用小结(crop和paste函数)