超卖问题:在一个很短的时间内,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做测试工具)的更多相关文章

  1. 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想试试,我 ...

  2. 关于IDEA中web项目中web.xml配置文件标红的解决办法

    原文链接 https://blog.csdn.net/qq_33451695/article/details/86684127 解决方法前提:web.xml没有实际错误,但依然被web.xml标红 出 ...

  3. 关于CUDA C 项目中“ error C2059: 语法错误:“<” ”问题的解决方法

    该问题的关键在于理解CUDA项目中C\C++文件需要由c++编译器进行编译,而CUDA C的源文件需要由CUDA的编译器nvcc.exe进行编译. 发生该语法错误的原因是cu文件被C++编译器所编译, ...

  4. eclipse中的js文件报错的解决办法

    在使用别人的项目的时候,导入到eclipse中发现js文件报错,解决办法是关闭eclipse的js校验功能. 三个步骤: 1. 右键点击项目->properties->Validation ...

  5. Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)

    当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...

  6. [转]iOS Safari 中click点击事件失效的解决办法

    iOS Safari 中click点击事件失效的解决办法 问题起因: 在微信公众号开发(微站)过程中用jquery的live方法绑定的click事件点击无效(不能执行) 问题描述 当使用委托给一个元素 ...

  7. python matplotlib plot 数据中的中文无法正常显示的解决办法

    转发自:http://blog.csdn.net/laoyaotask/article/details/22117745?utm_source=tuicool python matplotlib pl ...

  8. 配置IIS提示打开目录浏览时的问题:未能从程序集“System.ServiceModel, Version=3.0.0.0”中加载类型“System.ServiceModel.Activation.HttpModule” 的解决办法

    错误消息: 未能从程序集“System.ServiceModel, Version=3.0.0.0”中加载类型“System.ServiceModel.Activation.HttpModule” 的 ...

  9. Android 在 Fragment 中使用 getActivity() NullPointException 的思考和解决办法

    问题: 使用 AS 在 Fragment 中调用 getActivity() 方法的时候会出现可能为空指针的提醒 使用 monkey 多次十万次测试,会出现 getActivity() NullPoi ...

随机推荐

  1. BERT的几个可能的应用

      BERT是谷歌公司于2018年11月发布的一款新模型,它一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的"语言理解"模型,然后用这个模型去执行想做的NLP ...

  2. hdu1879 继续畅通工程 基础最小生成树

    #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> u ...

  3. 一些CSS的备忘

    text-transform 文本转换 属性值是 none表示没有 不转换 同时也是默认的 capitalize 表示首字母大写 uppercase全部转换为大写 lowercase全部转为小写 te ...

  4. 用JS改变页面中b标签的样式啊 样式的等

    用JS改变页面中b标签的样式啊 样式的等    ,实际上是在标签内加上样式 ,用媒体查询的话 ,不能生效 <!DOCTYPE html> <html lang="en&qu ...

  5. Appium安装说明

    1.安装Appium前,需要先安装node.js .node.js官方网站:https://nodejs.org/, 这里我以Windows 10为例进行安装,选择Windows installer( ...

  6. AtCoder Grand Contest 017 A

    Problem Statement There are N bags of biscuits. The i-th bag contains Ai biscuits. Takaki will selec ...

  7. 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 ...

  8. (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting

    题目传送门 题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...

  9. SpringCloud开发学习总结(八)—— API网关服务Zuul(一)

    大多数情况下,为了保证对外服务的安全性,我们在服务端实现的为服务接口时往往都会有一定的权限校验机制,比如对用户登录状态的校验等:同时为了防止客户端在发起请求时被篡改等安全方面的考虑,还会有一些签名校验 ...

  10. Backbone学习记录(7)

    事件委托 <form> <input type="text" class="txt"> <input type="but ...