分布式mysql更新_高并发、分布式数据库场景下需要注意的 UPDATE SQL 写法

业务模块

超级话题签到积分

具体场景

更新签到积分行为

integration_record – 每次产生积分行为的记录表。即每当用户产生积分行为(如:在超级话题内进行签到、转发和回复等行为),就会增加一条integration_record表的记录。表明该用户在该超级话题下通过哪些行为产生了多少积分增量。

integration – 每个用户的总积分表。即在每次写入一条integration_record记录后,会将积分增量累计加入到该表的总积分字段中。表明目前为止,该用户在该超级话题下通过积分行为一共获取的积分总数。

表的细节就不给出了(也没必要)。这两张表都以话题ID(topic_id)和用户ID(uid_id)进行联合索引。

具体问题

在某些情况下,某个用户所在某个话题下的所有integration_record记录的积分总和小于该用户在该话题下的integration表记录的总积分。

异常日志

通过检查线上异常日志发现,会偶发出现更新integration表记录返回0(更新影响记录行数为0)的情况。但理论上不应该出现这种情况。

分析

进而考虑是由于数据库主从同步的延迟导致。为什么这么猜测?看下面SQL:

update integration set integration = ? where topic_id = ? and uid = ?

上面为改动前(有问题)的SQL。其中第一个问号代表当前需要更新的积分总数。问题就出现在这个总数上。

这个总数是由当前用户产生的积分行为所增加分数与当前integration表中该用户的积分总数(读于从库)之和。

所以,在高并发的请求下,会出现同时待同步如下一些SQL:

update integration set integration = 1720 where topic_id = abc and uid = 12345678

update integration set integration = 1720 where topic_id = abc and uid = 12345678

之所以会出现如上第二条SQL的情况(integration值相同),就是因为在算当前integration字段值的时候,从库并没有完成第一条SQL的同步操作。

b6cc388dgw1f6mrf5l5m1j20c809gdgs.jpg

解决

所以,该问题就迎刃而解了。将SQL改成如下形式:

update integration set integration = integration + ? where topic_id = ? and uid = ?

注:该文章涉及业务敏感信息均已被处理。如有风险,请联系站长以及时处理。

转载请注明出处,违者必究!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值