• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

问一个mysql并发问题?

php 搞代码 4年前 (2022-01-25) 25次浏览 已收录 0个评论
文章目录[隐藏]

业务逻辑是这样的:

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

id,time是复合主键

业务流程:

<code>sql_1:select * from tb where id=$id and time=$tif (sql_1)    sql_2:updata from tb set num = num + 1 where id=$id and time=$telse    sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)</code>

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

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

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

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

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

谢谢大家了。

回复内容:

业务逻辑是这样的:

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

id,time是复合主键

业务流程:

<code>sql_1:select * from tb where id=$id and time=$tif (sql_1)   <strong style="color:transparent">¥本文来源gaodai#ma#com搞@@代~&码网^</strong><small>搞gaodaima代码</small> sql_2:updata from tb set num = num + 1 where id=$id and time=$telse    sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)</code>

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

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

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

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

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

谢谢大家了。

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

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

2.悲观锁for update

<code>select * from tb where id=$id and time=$t for updateif (sql_1)    sql_2:updata from tb set num = num + 1 where id=$id and time=$telse    sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)</code>

没人回答么?

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

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

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

<code>import threadinglock = threading.Lock()with lock:    # done something</code>

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

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

else

<code>sql_2_:INSERT INTO tb (id,time,num) values ($id,$t,1)</code>

unlock

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


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:问一个mysql并发问题?

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址