项目中遇到的超卖问题及解决办法(使用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 ...
随机推荐
- BERT的几个可能的应用
BERT是谷歌公司于2018年11月发布的一款新模型,它一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的"语言理解"模型,然后用这个模型去执行想做的NLP ...
- hdu1879 继续畅通工程 基础最小生成树
#include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> u ...
- 一些CSS的备忘
text-transform 文本转换 属性值是 none表示没有 不转换 同时也是默认的 capitalize 表示首字母大写 uppercase全部转换为大写 lowercase全部转为小写 te ...
- 用JS改变页面中b标签的样式啊 样式的等
用JS改变页面中b标签的样式啊 样式的等 ,实际上是在标签内加上样式 ,用媒体查询的话 ,不能生效 <!DOCTYPE html> <html lang="en&qu ...
- Appium安装说明
1.安装Appium前,需要先安装node.js .node.js官方网站:https://nodejs.org/, 这里我以Windows 10为例进行安装,选择Windows installer( ...
- AtCoder Grand Contest 017 A
Problem Statement There are N bags of biscuits. The i-th bag contains Ai biscuits. Takaki will selec ...
- Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) E
Description Bear Limak prepares problems for a programming competition. Of course, it would be unpro ...
- (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting
题目传送门 题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...
- SpringCloud开发学习总结(八)—— API网关服务Zuul(一)
大多数情况下,为了保证对外服务的安全性,我们在服务端实现的为服务接口时往往都会有一定的权限校验机制,比如对用户登录状态的校验等:同时为了防止客户端在发起请求时被篡改等安全方面的考虑,还会有一些签名校验 ...
- Backbone学习记录(7)
事件委托 <form> <input type="text" class="txt"> <input type="but ...