php - 问一个mysql并发问题?
天蓬老师
天蓬老师 2017-04-10 16:45:29
[PHP讨论组]

业务逻辑是这样的:

统计某一文章每一天的获赞次数:
tb(id,time,num)
id:文章ID
time:2016-1-31

id,time是复合主键

业务流程:

sql_1:select * from tb where id=$id and time=$t
if (sql_1)
    sql_2:updata from tb set num = num + 1 where id=$id and time=$t
else
    sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)

就是这样的很简单逻辑,本来没有什么问题,可是最近老是出错,原因是因为插入重复的复合主键,我才知道这样设计有并发的问题(两个进程同时判断通过,就会导致sql_2_执行两次而出错);

网上有很多讲这样的知识的,乐观锁,悲观锁等,但是都是将一些理论知识,一遇到实际问题,就没人理你了,书本上也基本是理论知识,没有实际问题的解决方法,我没有经验,不知道怎么解决这个问题,不想用乐观锁,需要要建一个version字段觉得不爽,程序多个地方用到时还不好控制。

意识到这个问题之后,我发现我之前所有的代码其实都会有这个问题,我相信上面这个逻辑是个非常基本的逻辑,我没想到会有这样的问题,好恐怖;

如果需要用到事务,我就把表全改为innodb的;

希望高人指点,就我上面的例子说实际的解决办法,不要找一些理论知识我看了。

谢谢大家了。

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

全部回复(6)
伊谢尔伦

实名反对以上答案!!!
mysql:
1.ON DUPLICATE KEY UPDATE语句
ID,time复合主键

INSERT INTO tb (id,time,num) values ($id,$t,1) ON DUPLICATE KEY UPDATE num=num+1;

2.悲观锁for update

select * from tb where id=$id and time=$t for update
if (sql_1)
    sql_2:updata from tb set num = num + 1 where id=$id and time=$t
else
    sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)
巴扎黑

没人回答么?

PHP中文网

这个可以在转发mysql请求,使用memcache独占锁,

迷茫

最简单的办法是将任务全部放到队列中去,然后使用单线程不断处理这个任务队列中的任务,这样解决了并发问题,但是效率就变低了。

我在用多线程写文件的时候也遇到过多线程同时写文件的问题,这个时候用线程锁(Python):

import threading
lock = threading.Lock()
with lock:
    # done something
黄舟

使用redis实现分布式锁,锁的位置如下
lock
sql_1:select * from tb where id=$id and time=$t
if (sql_1)

sql_2:updata from tb set num = num + 1 where id=$id and time=$t

else

sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)

unlock

怪我咯

我说过 我去年看过的一解决办法,我举个不切实际(ps:但是我觉得这个解决办法还是蛮好的,你可以去看一下《redis实战》这本书)的个例子,你创建100条数据,关联一篇新的文章,然后如果有更新,随机的更新1-100的数据 +1 。等到了一个合适的时候,把这100条合并成1条

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号