项目中遇到的超卖问题及解决办法(使用go做测试工具)
超卖问题:在一个很短的时间内,Mysql的数据状态在 取出,比较,提交,或修改中,另外一个进程访问数据导致的超卖问题。
案例:
1.前端没有做限制,如果用户连续点击签到,那么会有多条数据发送到后端,如果数据状态没有来得及完全修改过来,导致用户的签到数据被多次添加。
2.每天签到用户的前3名用户可以获得一张价值100元的优惠券,如果有多名用户在很短的时间内同时签到,那么就会有多发的问题。
一 .使用表锁,解决案例1中的问题
1.1 新建一张用户签到表
DROP TABLE
IF EXISTS `crm_concurrency`; CREATE TABLE `crm_concurrency` (
`id` INT (10) UNSIGNED NOT NULL AUTO_INCREMENT,
`member_id` INT (10) UNSIGNED DEFAULT NULL, -- 会员ID
`sign_date` date DEFAULT NULL, -- 签到日期
`create_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
1.2 添加签到记录逻辑
public function addSignValue(){
//会员ID
$member_id = I('get.member_id');
if(!$member_id){
return false;
}
//签到日期
$sign_date = date('Y-m-d');
$where_condition = array(
'member_id' =>$member_id,
'sign_date' =>date('Y-m-d')
);
//查询用户是否已经签到过
$sign_value = M('concurrency','crm_')
->where($where_condition)->find();
if(!$sign_value){
$add_value = array(
'member_id' =>$member_id,
'sign_date' =>$sign_date
);
//给未签到用户 添加一条签到记录
M('concurrency','crm_')->add($add_value);
}
}
1.3 Go压力测试代码
func fGet(url string) {
res, err := http.Get(url)
defer res.Body.Close()
if err != nil {
log.Fatal(err)
}
re, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(re))
ch <- struct{}{}
}
var ch = make(chan struct{})
func main() {
url := "测试URL?member_id=";
for index := 1; index <= 10; index++ {
tmp := url + strconv.Itoa(1) ;
go fGet(tmp)
}
for index := 1; index <= 10; index++ {
<-ch
}
}
1.4 加上lock(true)可以解决问题。实际就是在查询语句最后加上 for update,这里用到了表锁。
public function addSignValue(){//锁表
M('')->startTrans();
$sign_value = M('concurrency','crm_') ->where($where_condition) ->lock(true) ->find(); if(!$sign_value){ $add_value = array( 'member_id' =>$member_id, 'sign_date' =>$sign_date ); //添加一条签到记录 M('concurrency','crm_')->add($add_value); }
M('')->commit();
}
//SELECT * FROM `crm_concurrency` WHERE `member_id` = 1 AND `sign_date`
//= '2017-12-25' LIMIT 1 FOR UPDATE
二 .使用行锁,解决案例2中的问题
1.新建一张签到发券配置表和发券表,这里只建了一个配置表做演示
DROP TABLE IF EXISTS `crm_coupons_config`;
CREATE TABLE `crm_coupons_config` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`config_count` int(10) unsigned DEFAULT NULL COMMENT '要发放券的数量',
`has_given` int(255) unsigned DEFAULT NULL COMMENT '已发放的券的数量',
`create_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.下面是第一种思路的伪代码,也使用了表锁
public function sendCoupons(){
//1.从crm_coupons_config表中取出配置
//2.锁住发券表,并计算已经发的券的数量
//3.如果已发的券的数量大于等于配置表的数量,则停止发送券
}
3.下面是另外一一种思路,使用到了行锁。不需要添加额外锁表代码,因为mysql在查询,更新 的时候,是默认锁表的
public function sendCoupons(){
$req = M('coupons_config','crm_')
->where('config_count>has_given')
->setInc('has_given');
if($req){
//申请到了优惠券
}
}
//UPDATE `crm_coupons_config` SET `has_given`=has_given+1 WHERE ( config_count>has_given )
三 总结
主要使用到了数据库中的表锁和行锁
项目中遇到的超卖问题及解决办法(使用go做测试工具)的更多相关文章
- ASP.NET CORE MVC 2.0 项目中引用第三方DLL报错的解决办法 - InvalidOperationException: Cannot find compilation library location for package
目前在学习ASP.NET CORE MVC中,今天看到微软在ASP.NET CORE MVC 2.0中又恢复了允许开发人员引用第三方DLL程序集的功能,感到甚是高兴!于是我急忙写了个Demo想试试,我 ...
- 关于IDEA中web项目中web.xml配置文件标红的解决办法
原文链接 https://blog.csdn.net/qq_33451695/article/details/86684127 解决方法前提:web.xml没有实际错误,但依然被web.xml标红 出 ...
- 关于CUDA C 项目中“ error C2059: 语法错误:“<” ”问题的解决方法
该问题的关键在于理解CUDA项目中C\C++文件需要由c++编译器进行编译,而CUDA C的源文件需要由CUDA的编译器nvcc.exe进行编译. 发生该语法错误的原因是cu文件被C++编译器所编译, ...
- eclipse中的js文件报错的解决办法
在使用别人的项目的时候,导入到eclipse中发现js文件报错,解决办法是关闭eclipse的js校验功能. 三个步骤: 1. 右键点击项目->properties->Validation ...
- Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)
当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...
- [转]iOS Safari 中click点击事件失效的解决办法
iOS Safari 中click点击事件失效的解决办法 问题起因: 在微信公众号开发(微站)过程中用jquery的live方法绑定的click事件点击无效(不能执行) 问题描述 当使用委托给一个元素 ...
- python matplotlib plot 数据中的中文无法正常显示的解决办法
转发自:http://blog.csdn.net/laoyaotask/article/details/22117745?utm_source=tuicool python matplotlib pl ...
- 配置IIS提示打开目录浏览时的问题:未能从程序集“System.ServiceModel, Version=3.0.0.0”中加载类型“System.ServiceModel.Activation.HttpModule” 的解决办法
错误消息: 未能从程序集“System.ServiceModel, Version=3.0.0.0”中加载类型“System.ServiceModel.Activation.HttpModule” 的 ...
- Android 在 Fragment 中使用 getActivity() NullPointException 的思考和解决办法
问题: 使用 AS 在 Fragment 中调用 getActivity() 方法的时候会出现可能为空指针的提醒 使用 monkey 多次十万次测试,会出现 getActivity() NullPoi ...
随机推荐
- 移动端rem.js的使用方法
下面的代码一是我根据rem的使用经验,自己写的一个rem.js,发现很好用,能适用所有移动端h5页面的自适应需求: 代码一: window.onload = function(){ /*720代表设计 ...
- SqlParameter 操作 image 字段
public static void AddEmployee( string lastName, string firstName, string title, DateTime hireDate, ...
- python tkinter窗口弹出置顶的方法
加上下面两句即可实现root窗口的置顶显示,可以用于某些程序的消息提示,能够弹出到桌面显示 root = Tk() root.wm_attributes('-topmost',1)
- RHEL6.5---LVS(IP-TUN)
实验环境: 主机名 IP 所需软件 master eth0==>192.168.30.160(RIP) eth0:1==>192.168.30.130(VIP) ipvsadm node ...
- 记一次有关spark动态资源分配和消息总线的爬坑经历
问题: 线上的spark thriftserver运行一段时间以后,ui的executor页面上显示大量的active task,但是从job页面看,并没有任务在跑.此外,由于在yarn mode下, ...
- python工具之日志记录
''' 写日志类 日志存放目录为当前应用程序的目录下的log目录中 日志产生规则:每小时产生一个文件 write by :wujf 2017-02-24 ''' import sys import o ...
- Backbone.js之Todo源码浅析
相信每个接触了解过backbone的人都知道todo,网上的关于它的分析教程也都分析乱了.但是,知识只有自己学习领悟才是自己的,话不多说,正文开始. 在分析todo的源码之前,首先我们要知道todo具 ...
- (转)新手学习System Verilog & UVM指南
从刚接触System Verilog以及后来的VMM,OVM,UVM已经有很多年了,随着电子工业的逐步发展,国内对验证人才的需求也会急剧增加,这从各大招聘网站贴出的职位上也可以看出来,不少朋友可能想尽 ...
- windows系统下查看或删除自己电脑的共享文件以及文件夹
(1)查看所有共享 net share (2)删除指定共享 例如:删除C盘共享 net share C$ /delete net share 共享名 /delete (/del)
- vue路由高级语法糖
1.当 <router-link> 对应的路由匹配成功,将自动设置 class 属性值 .router-link-active. 模板中可以用{{$route.params.xxx取到路由 ...