弃用悲观锁

简介: 【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来确保数据没有发生更改。
可以聊到乐观锁的情况下,用这个案例。

目录
相关文章
|
1月前
|
数据库 开发者
使用版本号实现乐观锁
使用版本号实现乐观锁
|
3月前
|
SQL 关系型数据库 MySQL
MySQL数据库——锁-概述以及全局锁(介绍、语法、特点)
MySQL数据库——锁-概述以及全局锁(介绍、语法、特点)
55 0
|
4月前
|
数据库连接 数据库
多线程事务失效的原因
【5月更文挑战第16天】多线程事务失效的原因
287 0
|
SQL 存储 Oracle
19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍|学习笔记
快速学习19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍
668 0
19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍|学习笔记
|
算法
悲观锁和乐观锁的区别
悲观锁和乐观锁的区别
215 0
|
关系型数据库 索引
上手隐式锁,显式锁
上手隐式锁,显式锁
上手隐式锁,显式锁
|
关系型数据库 中间件 MySQL
上手全局锁,死锁
上手全局锁,死锁
上手全局锁,死锁
|
存储 关系型数据库 MySQL
MySQL的表级锁、行级锁、页级锁是干什么的?底层原理是什么?
MySQL的表级锁、行级锁、页级锁是干什么的?底层原理是什么?
411 0
|
数据采集 算法 Java
锁住它,快告诉我乐观锁与悲观锁的区别?
锁住它,快告诉我乐观锁与悲观锁的区别?
134 1
锁住它,快告诉我乐观锁与悲观锁的区别?
|
SQL 关系型数据库 MySQL
事务丢失更新问题及乐观锁、悲观锁机制
事务丢失更新问题及乐观锁、悲观锁机制
258 0
事务丢失更新问题及乐观锁、悲观锁机制