超卖问题:在一个很短的时间内,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. 决斗(Headshot )

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ; char ...

  2. Asp.net core 框架整理

    https://github.com/thangchung/awesome-dotnet-core#cms

  3. Ilya And The Tree CodeForces - 842C

    ((半个)智商题,主要难度在于实现) 题意:有一棵n个结点组成的树,其根是编号为1的结点.对于每一个结点,生成从根结点走到这个结点的路径(包括自身),选择路径上的一个点或者不选择任何点,使得其它点的最 ...

  4. 修改dns访问android.com

    1.几个常用dns服务器 8.8.8.8 美国 加利福尼亚州圣克拉拉县山景市谷歌公司DNS服务器 8.8.4.4 美国 加利福尼亚州圣克拉拉县山景市谷歌公司DNS服务器 8.8.4.3 美国 加利福尼 ...

  5. [已读]响应式web设计实践

    薄的一本,彩印,书质量和内容都不错. 响应设计三要素:媒体查询.流动布局.自适应图片.

  6. RHEL 6.5----SCSI存储

    主机名 IP master 192.168.30.130 node-1 192.168.30.131 node-2 192.168.30.132 安装并启动 [root@master ~]# ll / ...

  7. 微信小程序九宫格布局

    先上效果图 使用注意事项 1:注意在app.json中注册页面路径 2:如果要增加新的Item,可到js中对listService数组进行增加 3:listService参数[ title:分类标题 ...

  8. Win10 隐藏盘符

    1.隐藏盘符 打开磁盘管理 -> 对要隐藏的盘符单击右键 -> 更改驱动器号和路径 -> 删除. 打开资源管理,已经看不到该盘符,该盘符已被隐藏.只是隐藏,该盘符上的数据仍然还在. ...

  9. ios https 安全证书配置

    原定于2017年1月1日起所有提交到 App Store 的App必须强制开启 ATS,需要配置Https.但是现在不需要了,无固定期限的往后延期了,但是这个还是得弄明白下为好,说不定哪天突然就让弄了 ...

  10. TCP/IP详解之IP协议

    1.IP协议 IP协议是TCP/IP协议的核心,所有的TCP,UDP,IMCP,IGCP的数据都以IP数据格式传输.要注意的是,IP不是可靠的协议,这是说,IP协议没有提供一种数据未传达以后的处理机制 ...