弃用悲观锁

简介: 【8月更文挑战第4天】

从理论上来说,解决方案有三种:

  • 不管有没有数据,先插入一个默认的数据。如果没有数据,那么会插入成功;如果有数据,会出现主键冲突或唯一索引冲突,插入失败。在插入成功的时候,执行以前数据不存在的逻辑,因为此时数据库里有数据,所以不会使用间隙锁,而是使用行锁,从而规避了死锁问题。
  • 调整数据库的隔离级别,降低为已提交读就没有间隙锁了。可以进一步把话题引申到MVCC中。
  • 放弃悲观锁,使用乐观锁。这也是亮点方案。

可以通过一个案例说明,关键词是临键锁。

早期优化过一个死锁问题,是临键锁引起的,业务逻辑很简单,先用 SELECT FOR UPDATE 查询数据。如果查询到了数据,那么就执行一段业务逻辑,然后更新结果;如果没有查询到,那么就执行另外一段业务逻辑,然后插入计算结果。
那么如果 SELECT FOR UPDATE 查找的数据不存在,那么数据库会使用一个临键锁。此时,如果有两个线程加了临键锁,然后又希望插入计算结果,那么就会造成死锁。
我这个优化也很简单,就是上来先不管三七二十一,直接插入数据。如果插入成功,那么就执行没有数据的逻辑,此时不会再持有临键锁,而是持有了行锁。如果插入不成功,那么就执行有数据的业务逻辑。
此外,还有两个思路。一个是修改数据库的隔离级别为 RC,那么自然不存在临键锁了,但是这个修改影响太大,被 DBA 否决了。另外一个思路就是使用乐观锁,不过代码改起来要更加复杂,所以就没有使用。

后续可能会追问隔离级别的事情,或是问乐观锁的细节。

很多人为了省事会直接使用悲观锁,比如事务里存在SELECT ... FOR UPDATE的语句,而后面紧跟一个UPDATE语句

// 开启事务
Begin()
// 查询到已有的数据 SELECT * FROM xxx WHERE id = 1 FOR UPDATE
data := SelectForUpdate(id) 
newData := calculate(data) // 一大通计算

// 将新数据写回去数据库 UPDATE xxx SET data = newData WHERE id =1
Update(id, newData) 
Commit()

考虑这一类代码直接把事务给去掉,纯粹依赖CAS操作

for {
  // 查询到已有的数据 SELECT * FROM xxx WHERE id = 1
  data := Select(id) 
  newData := calculate(data) // 一大通计算

  // 将新数据写回去数据库 
  // UPDATE xxx SET data = newData WHERE id =1 AND data=oldData
  success := CAS(id, newData, data) 
  // 确实更新成功,代表在业务执行过程中没有人修改过这个 data。
  // 适合读多写少的情况
  if success {
    break;
  }
}

这里是直接用data来比较的,实践中也可能引入version列,或是update_time来确保数据没有发生更改。
可以聊到乐观锁的情况下,用这个案例。

目录
相关文章
Debian 官方源换为国内的源的操作方法
apt-get update 报错,采用更换源的方式解决问题。
57354 0
|
NoSQL 程序员 Linux
轻踩一下就崩溃吗——踩内存案例分析
踩内存问题分析成本较高,尤其是低概率问题困难更大。本文详细分析并还原了两个由于动态库全局符号介入机制(it's a feature, not a bug)触发的踩内存案例。
|
机器学习/深度学习 人工智能 算法
AI技术在医疗领域的应用与挑战
【5月更文挑战第31天】本文将探讨AI技术在医疗领域的应用及其所面临的挑战。随着科技的发展,AI技术已经在许多领域得到广泛应用,其中包括医疗领域。然而,尽管AI技术在医疗领域的应用带来了许多好处,但仍然面临着一些挑战。本文将详细介绍AI技术在医疗领域的应用以及这些挑战,并探讨如何克服这些挑战以实现更好的医疗服务。
|
Linux 开发工具
Ext4 开启 project quota
# quota 介绍 ## project quota 介绍 quota 子系统用于限制磁盘的使用量。 从限制的主体进行分类,quota 包含 user quota、group quota 与 project quota 三部分。顾名思义,user quota、group quota 限制的主体分别是 user、user group,而 project quota 限制的主体则是
5613 0
|
Kubernetes NoSQL Redis
【kubernetes】二进制方式安装 containerd
【kubernetes】二进制方式安装 containerd
2173 1
【kubernetes】二进制方式安装 containerd
|
Linux
Linux系统【系统管理】resize2fs命令 – 同步文件系统容量到内核
resize2fs命令来自于英文词组“resize to filesystem”的缩写,其功能是用于同步文件系统容量到内核。如对ext3、ext4、XFS等设备卷容量进行了调整,则需要使用resize2fs命令同步信息到系统内核。
705 0
|
Ubuntu Linux
Vagrant Box 镜像配置国内源
Vagrant Box 镜像配置国内源
2707 0
|
SQL 安全 前端开发
HTB:Charon渗透测试(二)
HTB:Charon渗透测试
219 0
HTB:Charon渗透测试(二)
|
缓存 运维 监控
长文解析:作为容器底层技术的半壁江山, cgroup如何突破并发创建瓶颈?
io_uring 作为一种新型高性能异步编程框架,代表着 Linux 内核未来的方向,当前仍处于快速发展中。阿里云联合 InfoQ 发起《io_uring 介绍及应用实践》的技术公开课,围绕 OpenAnolis 龙蜥社区 Anolis OS 8 全方位解析高性能存储场景。
长文解析:作为容器底层技术的半壁江山, cgroup如何突破并发创建瓶颈?

热门文章

最新文章