【转】记录PHP、MySQL在高并发场景下产生的一次事故
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了【转】记录PHP、MySQL在高并发场景下产生的一次事故,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含1479字,纯文字阅读大概需要3分钟。
内容图文
看了一篇网友日志,感觉工作中值得借鉴,原文如下:
事故描述
在一次项目中,上线了一新功能之后,陆陆续续的有客服向我们反应,有用户的个别道具数量高达42亿,但是当时一直没有到证据表示这是,确实存在,并且直觉告诉我们,这是不可能的,就一直没有在意,直到后来真的发现了一个用户确实是42亿,当时我们整个公司都震惊了,如果有大量用户是这样的情况,公司要亏损几十万,我们的老大告诉我们,肯定是什么地方数据溢出的,最后我们一帮人,疯了似的查代码,发现……
如果按照正常的程序逻辑走下去,代码是完全没问题,但是我发现了一个地方,如果在高并发的情况下,是会走出错误的程序逻辑的,为什么我看到了,很简单,我在上一家公司,因为这个问题困扰了我一个多月,真是刻骨铭心呀!不多说了,说多了都是泪呀!上代码,重现场景(以下都是一些简单的代码,用来重现场景),道具名就定义为props。
<?php mysql_connect("localhost", "mysql_user", "mysql_password"); mysql_select_db("user"); $consume_props_count = 10; // 要消耗的道具数量$select = ‘SELECT `count` from `user` where `userid`=123456‘; $query = mysql_query($select); $row = mysql_fetch_assoc($query); // 对比当前道具数量if ($row[‘count‘] < $consume_props_count) { returnfalse; } // 扣除道具数量$update = "update `user` set `count`=`count`-{$consume_props_count}"; $query = mysql_query($update); returnmysql_num_rows($query); ?>
大家可以看到,如果按照正常的扣除道具的流程来走,这个是没有问题的,但是在高并发场景下,两次扣道具的查询极有可能获取的是同一个结果,然后他们都能通过对比当前道具数量这一步逻辑,但是加入第一次的扣道具的操作把道具扣光了,或者扣的不够第二次继续扣了,想想会发生什么样的情况!
坑爹了!第二次会把道具数量扣为负数。
但是这依然不能解释这42亿的溢出那里来的!哎,祸不单行的古语再次应验了,我们的count字段的数据类型是Unsigned int,坑爹的MySQL,假如字段是Unsigned int,然后输入了一个负数,它就会让这个数字变为42亿这个巨大的数值。
看明白了吧!这42亿就是这么来的,坑啊!
解决方案的话,可以在update的sql改成这样
1
|
<?php
|
2
|
$update = "UPDATE `user` SET `count`=(CASE WHEN `count`<={$consume_props_count} THEN 0 ELSE `count`-{$consume_props_count} END) WHERE `userid`=123456" |
3
|
?>
|
这样,就不会在扣成负数了,另外以防万一,还要将Unsigned int的字段类型,改为int。
原文:http://www.cnblogs.com/qxbj/p/4310297.html
内容总结
以上是互联网集市为您收集整理的【转】记录PHP、MySQL在高并发场景下产生的一次事故全部内容,希望文章能够帮你解决【转】记录PHP、MySQL在高并发场景下产生的一次事故所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。