大坑后记: sql事务关于select for update那点事

本文通过一个具体的场景,探讨了在处理数据库事务时,由于并发导致的消息记录未被正确删除的问题。分析指出,即使在事务中,简单的select后再update也可能引发不一致性。解决方案是使用`select for update`来锁定数据,确保事务处理过程的安全性。文章以实例解析了`select for update`如何避免并发更新带来的问题,并总结了这一经验教训。
摘要由CSDN通过智能技术生成

1.场景描述

这是开发中的一个项目,有以下场景:

  1. 对于一条消息m,有若干个接收者(r1, r2)。
  2. 接收者(假设为r1)收到消息后,发送确认消息。
  3. 收到r1的确认消息后,服务器从消息m的接收者中删除对应的接收者(r1)。
  4. 服务器检查消息m的接收者队列,如果为空,则删除消息M

在极偶然的情况下,竟然发现,当r1,r2都发出了消息确认,而消息M的数据库记录中的接收者队列也确实是空,但是消息M竟然没被删除!

2.伪代码

 服务器关于接收确认消息的处理伪代码大概如下:

// 开启事务
begin_transaction()
// 从db中找到消息m
// select * from M where id = some_id
m = find(some_id)
// 从db中找到消息m的接收者
receivers = find_receivers(m)
// 从db中删除消息m的接收者r
del_receiver(m, r) 
// 从receivers中删除该接收者r
receivers = remove(receivers, r)
if (receivers.empty()) {
    // 如果接收者队列为空,即没有接收者了,则删除消息m
    del_m(m)
}
commit_transaction()

3.疑问

如果简单的把事务当成锁的话,那上面的逻辑无懈可击,因为最后一个确认消息到达后,消息的接收者队列必然会清空,消息肯定会被删除。但残酷的现实表示,不一致状态还是出现了:消息的接收者队列是空的,但是消息没有被删除。

发生这种情况的唯一解释就是,r1,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值