看了一篇网友日志,感觉工作中值得借鉴,原文如下:

事故描述

在一次项目中,上线了一新功能之后,陆陆续续的有客服向我们反应,有用户的个别道具数量高达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) {
return false;
} // 扣除道具数量
$update = "update `user` set `count`=`count`-{$consume_props_count}";
$query = mysql_query($update);
return mysql_num_rows($query);
?>

大家可以看到,如果按照正常的扣除道具的流程来走,这个是没有问题的,但是在高并发场景下,两次扣道具的查询极有可能获取的是同一个结果,然后他们都能通过对比当前道具数量这一步逻辑,但是加入第一次的扣道具的操作把道具扣光了,或者扣的不够第二次继续扣了,想想会发生什么样的情况!

坑爹了!第二次会把道具数量扣为负数。

但是这依然不能解释这42亿的溢出那里来的!哎,祸不单行的古语再次应验了,我们的count字段的数据类型是Unsigned int,坑爹的MySQL,假如字段是Unsigned int,然后输入了一个负数,它就会让这个数字变为42亿这个巨大的数值。

看明白了吧!这42亿就是这么来的,坑啊!

解决方案的话,可以在update的sql改成这样

<?php
$update = "UPDATE `user` SET `count`=(CASE WHEN `count`<={$consume_props_count} THEN 0 ELSE `count`-{$consume_props_count} END) WHERE `userid`=123456"
?>

这样,就不会在扣成负数了,另外以防万一,还要将Unsigned int的字段类型,改为int

摘自:http://h5b.net/php-mysql-high-concurrency-accident

【转】记录PHP、MySQL在高并发场景下产生的一次事故的更多相关文章

  1. HttpClient在高并发场景下的优化实战

    在项目中使用HttpClient可能是很普遍,尤其在当下微服务大火形势下,如果服务之间是http调用就少不了跟http客户端找交道.由于项目用户规模不同以及应用场景不同,很多时候可能不需要特别处理也. ...

  2. Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S

    Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...

  3. 高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器

    package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.a ...

  4. 高并发场景下System.currentTimeMillis()的性能问题的优化

    高并发场景下System.currentTimeMillis()的性能问题的优化 package cn.ucaner.alpaca.common.util.key; import java.sql.T ...

  5. C++高并发场景下读多写少的解决方案

    C++高并发场景下读多写少的解决方案 概述 一谈到高并发的解决方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也 ...

  6. C++高并发场景下读多写少的优化方案

    概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读 ...

  7. MySQL在大数据、高并发场景下的SQL语句优化和"最佳实践"

    本文主要针对中小型应用或网站,重点探讨日常程序开发中SQL语句的优化问题,所谓“大数据”.“高并发”仅针对中小型应用而言,专业的数据库运维大神请无视.以下实践为个人在实际开发工作中,针对相对“大数据” ...

  8. Mysql在高并发情况下,防止库存超卖而小于0的解决方案

    背景: 本人上次做申领campaign的PHP后台时,因为项目上线后某些时段同时申领的人过多,导致一些专柜的存货为负数(<0),还好并发量不是特别大,只存在于小部分专柜而且一般都是-1的状况,没 ...

  9. 高并发场景下System.currentTimeMillis()的性能优化

    一.前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法, 有时不得不使用, ...

随机推荐

  1. python基础===【爬虫】爬虫糗事百科首页图片代码

    import requests import re import urllib.request def getHtml(url): page = requests.get(url) html = pa ...

  2. Percona XtraDB Cluster(PXC)原理

    Percona XtraDB Cluster(PXC)原理 介绍: PXC曾经属于一套近乎最完美的mysql高可用集群解决方案(现mgr总体上要优于pxc),相比传统的基于主从复制模式的集群架构MHA ...

  3. selenium 点击浏览器按钮

    利用以下的方法,selenium 也可以模拟点击各种浏览器按钮:browser.back()点击“返回”按钮.browser.forward()点击“前进”按钮.browser.refresh()点击 ...

  4. sicily 数据结构 1014. Translation

    Description You have just moved from Waterloo to a big city. The people here speak an incomprehensib ...

  5. 4.Python3标准库--算法

    (一)functools:管理函数的工具 import functools ''' functools模块提供了一些工具来管理或扩展和其他callable对象,从而不必完全重写 ''' 1.修饰符 f ...

  6. UVALive 6426

    UVALive 6426 /** 题意:给一个n*m的矩阵,求某一个区间的数的数量 做法:刚开始想用树状数组,但是RE,题目中说数据是从二进制流中读入, 用scanf会挂掉 所以用fread 读入 s ...

  7. jenkins上展示html报告【转载】

    转至博客:上海-悠悠 前言 在jenkins上展示html的报告,需要添加一个HTML Publisher plugin插件,把生成的html报告放到指定文件夹,这样就能用jenkins去读出指定文件 ...

  8. oracle 11g安装教程

    oracle 11g安装教程 第1步 第2步 第3步 第4步 第5步 第6步 第7步 第8步 第9步 第10步 第11步 第12步 第13步 第14步 第15步 第16步 第17步 第18步 第19步 ...

  9. cocos2djs ctor init onEnter的区别

    cocos2d-html5 onEnter init ctor构造函数 ---js特有特性(和c++有点不一样 ctor 构造函数, new 一个对象的时候调用-----coco2d-js , 默认c ...

  10. HDU 2665.Kth number-可持久化线段树(无修改区间第K小)模板 (POJ 2104.K-th Number 、洛谷 P3834 【模板】可持久化线段树 1(主席树)只是输入格式不一样,其他几乎都一样的)

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...