浅谈乐观锁的设计

前言

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

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

关于数据库的乐观锁使用, 是不是很多人一看到乐观锁就会想到  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}

 

只要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 无锁算法 大家了解过么?

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

 

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

 

 

 

 

 

 

 

 

栏目
728_90 cn stocks