浅谈乐观锁的设计

简介: 浅谈乐观锁的设计

前言



大家对 乐观锁  这三个字眼应该不陌生吧?


为什么今天我想谈谈乐观锁的设计呢?


关于数据库的乐观锁使用, 是不是很多人一看到乐观锁就会想到  Version 字段 (版本标识)。


ps: 其实不是非要新增版本字段


正文



乐观锁 , Optimistic Concurrency Control (乐观并发控制),简称 OCC 。


乐观锁不是一种真正的 ‘ 锁 ’,而是一种实现锁效果的 设计思想:


乐观地 认为 并发的操作对数据 不会产生冲突,所以没有使用 真正的 ‘锁’ 去对数据加锁;


而是选择在提交数据的时候,去检测数据是否冲突了?


发现冲突就采取 处理操作,例如报错、重试、停止等等。


设计


基于数据库使用展开介绍


使用版本标识  version 字段


也就是在 表内 增加一个字段  version 。


每次写操作如果时成功的,都需要 将 version 版本值 +1 ,


例如原来 某条数据的 version值为  1, 如果修改了,那么 version就需要变成 version+ 1   , 也就是 2.  


然而在并发场景,大量的写操作不免会发生冲突。


所以当我们 读取 数据 且 需要做更新操作时。 我们的 设计流程时这样的:


1. 读取数据,把数据里的version值 取出作为  更新前标识 值  version-before。


2.做业务逻辑计算等等 ....


3. 更新数据操作 ,更新时, 将之前的 标识 值    version-before 与 数据库里面的  version值  做匹对, 检测是否一致。


如果一致, 那么意味着 这时段内,没有其他写操作修改过数据, 那么我们可以提交成功。


如果不一致,那么意味着 发生了写写冲突, 也就是我们此刻需要更新的数据,已经被修改过了。那么我们可以根据业务场景,采取处理措施 (报错记录、重试流程、停止等等)。


ps: 注意了,这里的读取,检测,更新  这些操作都是务必保证 操作的原子性 ,连贯执行,也就是处于同个事务内。


mysql语句的写法举例:


update proinfo  set proNum = proNum + 10 , version = version + 1 where version = #{version} and proId = #{proId}


image.png只要where 后的 version 条件不成立,那么就是更新不成功,也就是 检测到了 ‘冲突’  。


那么前言里,我提到 使用乐观锁,不一定非要新增版本 version字段。


我们还可以使用 updateTimestamp  这种字段值。


我想,大家接触过很多项目,是不是看到很多老项目的表内都会有个 更新时间(时间戳)的字段,


但是好像业务里又没有用。


其实,这种字段,可以用来实现 乐观锁。


精确到毫秒或者更细, 每次操作,读取数据前把 时间戳的值 保存,然后更新提交的时候, 将这时间戳和数据库内的时间戳 值做匹对,原理也是一样的。时间戳字段可以自己传入,也可以是通过mysql函数默认获取更新。


update proinfo set proNum = proNum + 10 , updateTimestamp = unix_timestamp(now())                                                        where  updateTimestamp = #{updateTimestamp} and  proId = #{proId}


(可能有人会反驳,如果时间戳一模一样呢? 我不多说、)


为什么需要提这个呢。 因为我想传达的是, 乐观锁,要理解这种 乐观控制的设计思想,灵活去运用。


而不是固化,看到千篇一律地加字段 version,就跟着加。


有时候有些老项目,不是说加个字段那么回事,也许会引发一些杂七杂八的问题。


那么我们大可去根据实际情况去设计乐观锁。  


那么最后也简单地说下这个数据库使用乐观锁设计,


1.最好是 读多写少的场景下使用,因为写的操作少了,也就更乐观了。


2. 在发现冲突时, 咱们的处理操作要慎重设计, 特别是写操作并发特别多的情况,采取 无限制地重试? 短时间会不会适得其反?  


思想很重要,不是只顾着去套模式,因为掌握了这种思想,也许你不单单在使用乐观锁的时候你才用得上。


最后给大家留个小话题, CAS 无锁算法 大家了解过么?


可以去了解下,再回来 看看 文中说的 数据库里乐观锁的设计思想。



该篇浅谈就到这,神神叨叨习惯了,说的东西可能没营养可能有营养,就到这吧。

相关文章
|
7月前
|
消息中间件 安全 Java
什么是乐观锁、在哪用过乐观锁
什么是乐观锁、在哪用过乐观锁
199 0
|
2月前
|
算法 Java 关系型数据库
何为乐观锁和悲观锁
何为乐观锁和悲观锁
|
4月前
|
SQL 缓存 NoSQL
乐观锁的实现
乐观锁的实现
|
5月前
|
数据库
乐观锁介绍
乐观锁介绍
|
XML 前端开发 Java
案例突破——悲观锁和乐观锁
案例突破——悲观锁和乐观锁
153 0
案例突破——悲观锁和乐观锁
|
算法
悲观锁和乐观锁的区别
悲观锁和乐观锁的区别
232 0
|
数据库
乐观锁和悲观锁的底层原理
乐观锁和悲观锁是并发编程中常用的两种锁机制,用于解决多线程或多进程环境下的并发访问问题。它们的底层原理和适用场景有所不同。
155 0
|
缓存 数据处理 数据库
悲观锁和乐观锁的区别和应用场景
悲观锁和乐观锁是并发控制中常用的两种锁机制,用于解决多线程环境下的数据一致性问题。它们在应对并发访问时采取了不同的策略,有不同的特点和适用场景。
1386 0
|
SQL 安全 关系型数据库
悲观锁和乐观锁的区别以及实现方式
悲观锁和乐观锁的区别以及实现方式详细解答
370 0