并发测试mysql_实践100个线程:一次MySQL数据并发问题
问题:
最近接触一个任务,多个线程需要频繁更新mysql的同一条数据,使用了脚本进行并发测试,结果发现数据结构与预期不一致。
数据表的结构类似如下:
操作数据的步骤依次是
- 先取出mysql中数据
- 应用程序中做赋值操作count = count + 1
- 最后update变更后的值到mysql中最近接触一个任务,需要频繁更新mysql的同一条数据,使用了脚本进行并发测试,结果发现数据结构与预期不一致。
最近整理了一些Java架构学习视频和大厂项目底层知识点,需要的同学欢迎私信我【Java】发给你~
先取出mysql中数据:
select count from table where id = #{id};
应用程序中java代码实现赋值操作count = count + 1:
int count = count + 1
最后update变更后的值到mysql中:
update table set count = #{count} where id = #{id};
多次使用脚本开启100个线程累积1w次过后,发现总是小于1w;
分析一下,线程T1 获取到id 为1 的记录后在内存中做了count的累积,若此时另一个线程T2 也获取了id为1 的记录并且做了count = count + 1 的积累,并且更新到了mysql,此时T1再去更新id=1的记录时,就覆盖了线程T2的修改。
到此,问题已经分析出,接下来要怎么解决呢?!
mysql中的锁
- 悲观锁
- mysql 中select for update版本读会加悲观锁,实际上就是行锁,如果此时有并发select 或者update 、delete 操作时就会发生锁排斥,直到前面这个行锁释放过后才能继续操作,另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描
- 乐观锁
- mysql中的乐观锁实际上是个逻辑的概念,常见的实现方式是添加个版本号version或者时间戳;每次在更新数据之前先做个compare 然后再set,即CAS 操作;回到我们的业务场景,数据表结构可以修改成如下图,每次更新前先比较version是否跟之前获取到的version一致,若一致则更新,否则失败;此时更新就类似:
update table set count = #{count} where id = #{id} and version= #{version};
乐观锁和悲观锁使用场景
- 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能、
- 悲观锁则适合频繁写入场景
来源:网易工程师-赵娟娟
看到这里的小伙伴,如果你喜欢这篇文章的话,别忘了转发、收藏、留言互动!
最近我新整理了一些Java资料,包含个人精选的Java架构学习视频、大厂实战知识点、大厂内部面试题,如果你需要的话,欢迎私信我!
如果对文章有任何问题,欢迎在留言区和我交流~
并发测试mysql_实践100个线程:一次MySQL数据并发问题相关推荐
- 并发测试神器,模拟一次超过 5 万的并发用户
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:blazemeter | 来源:t.cn/ES7 ...
- 并发工具类(四)线程间的交换数据 Exchanger
前言 JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...
- jmeter http并发测试设置教程(设置线程组,设置http,csv参数化,查看结果集)
配置流程
- Go 学习笔记(22)— 并发(01)[进程、线程、协程、并发和并行、goroutine 启动、goroutine 特点,runtime 包函数]
Go 语言通过编译器运行时( runtime ),从语言上支持了并发的特性. 虽然 Go 程序编译后生成的是本地可执行代码,但是这些可执行代码必须运行在Go 语言的运行时(Runtime )中.Go ...
- 微信支付 mysql_微信支付回调函数无法插入mysql数据
我想在微信支付成功后通过回调插入一个订单,其中订单需要填入地址字段.如下图,其中$data['address']为地址字段,是通过获取缓存的session来得到的,但是无论直接读取session还是将 ...
- apache并发测试工具ab为什么测不准
apache并发测试工具ab为什么测不准 发表于2年前(2013-03-21 12:13) 阅读(1146) | 评论(1) 1人收藏此文章, 我要收藏 赞0 3月21日 深圳 OSC 源创会正在 ...
- 负载测试,并发测试,压力测试区别
负载测试 1.定义:负载测试是逐渐增加系统负载,测试系统性能的变化,最终确定系统在满足性能指标的情况下所能承受的最大负载的测试. 2.目的:在不挂系统的情况下进行测试,使系统在最大压力下正常运行. 获 ...
- Java并发(二十一):线程池实现原理
一.总览 线程池类ThreadPoolExecutor的相关类需要先了解: (图片来自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8% ...
- MySQL多线程并发调优
学习MySQL数据库技术,一个非常重要的技能就是性能调优.通常情况下,都是自下而上的调优方法,主要包括运行环境.配置参数.SQL性能和系统架构设计调优等. 本文从多线程并发的角度进行的思考,简单描述M ...
最新文章
- uniapp防止多次点击_多次赔、不分组、价格低,守卫者3号真的这么“逆天”?...
- kettle分批处理大表数据_kettle-批量同步表数据
- 阿里内部禁用Executors创建线程池,为什么?
- jvm四:常量的本质含义以及助记符基本认识
- 【spring boot】ajax post提交遇到403
- 怎么把数据文件上传云服务器,怎么把数据上传导云服务器
- Java算法面试题:编写一个程序,将e:\neck目录下的所有.java文件复制到e:\jpg目录下,并将原来文件的扩展名从.java改为.jpg...
- 类型的设计--类型和成员基础(二)
- php文件出现UTF-8错误,php – 文件格式UTF8与BOM导致“标头已发送” – 错误
- 在保护继承中基类的共有成员_C++面向对象:C++ 继承
- QCon思考之通过Quora和Spotify案例,直击数据处理背后的魅影
- java 接受gsm信息_android 获取手机GSM/CDMA信号信息,并获得基站信息
- Android开发之科大讯飞语音合成与播报
- 优酷 DSP 广告投放系统架构实践
- Emscripten 单词_学会词根词缀,开启高效、快速地记忆英语单词模式
- C语言+EasyX库实现--绘制彩虹
- 正确判断无人机指向故障 让电子罗盘远离磁干扰
- 孝经白话:卿大夫章第四
- 接连霸榜,这门国产编程语言是真的强!
- Stata教程(6)---帮助功能