前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于数据库实现的 “乐观锁” 和 “悲观锁”

基于数据库实现的 “乐观锁” 和 “悲观锁”

原创
作者头像
软件书桌
发布2024-04-11 17:38:01
2410
发布2024-04-11 17:38:01

为什么需要锁?

有一个资源正在被操作的时候,不希望被其它人操作,此时就需要通过加锁来防止这种情况的出现。

不同线程互斥的访问共享资源,才能保证共享资源被操作的顺序性,。

锁是保证并发情况下数据一致性的一种工具方法,没有锁机制的作用就会产生冲突。

典型冲突:

更新丢失:一个事务覆盖了另一个事务的更新结果。

脏读:一个事务读取到其它完成一半事务的记录。

悲观锁

悲观锁又名 “悲观并发控制”,Pessimistic Concurrency Control(PCC)。

顾名思义,这种方式下对数据的修改持悲观态度,认为数据被并发修改的概率比较大,采取 “先加锁再修改” 的保守策略。

适用场景:

悲观锁比较重,适用于业务一致性要求较高的场景,例如:库存、费用等。

悲观锁不适用于并发较高的场景,一个事务锁定了某行数据,其它事务必须等待该事务结束,这样就影响了业务的执行效率。

乐观锁

Optimistic Locking,这种方式下认为数据一般不会造成冲突,所以在数据提交更新的时候才会对数据的冲突与否进行检测。

如果发生冲突,则返回错误信息,让用户决定如何处理。

适用场景:

乐观锁锁适合用于更新频率不高的场景,一般的业务管理系统并发要求不会太高,比较适合使用乐观锁。

高并发的场景中使用乐观锁并不合适,因为会产生大量的失败,应该想其它办法解决这种大量失败问题。

数据库悲观锁

对数据进行修改前,尝试为该记录加上排他锁(exclusive locking)。

加锁失败,则表明该数据正在被修改,需要等待或者抛出异常。

MySql Innodb 引擎:

代码语言:javascript
复制
//0.开始事务
begin; 

//1.查询出商品库存信息(适用 for update 对数据加锁)
select quantity from items where id=1 for update;

//2.修改商品库存为2
update items set quantity=2 where id = 1;

//3.提交事务
commit;

数据库乐观锁

  • CAS

Compare and Swap 技术,冲突检测和数据更新。

当多个线程尝试更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,可以再次尝试。

代码语言:javascript
复制
// 查询出商品库存信息,quantity = 3
select quantity from items where id=1;

// 修改商品库存为2
update items set quantity=2 where id=1 and quantity = 3;

修改的时候,如果库存数据和之前的查询到的库存数据不一致,则说明数据已经过期,已经被别人修改过了。

  • ABA 问题

比如说一个线程1从数据库中取出库存数3,这时候另一个线程2也从数据库中库存数3,并且线程2进行了一些操作将库存数变成了2,紧接着又将库存数变成3,这时候线程1进行CAS操作发现数据库中仍然是3,然后线程1操作成功。尽管线程1的CAS操作成功,但是不代表这个过程就是没有问题的。

解决方法:通过一个单独的可以顺序递增的version字段。

代码语言:javascript
复制
//查询出商品信息,version = 1
select version from items where id=1

//修改商品库存为2
update items set quantity=2,version = 3 where id=1 and version = 2;

乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现ABA问题,因为版本号只会增加不会减少。

除了 version 以外,还可以使用时间戳,因为时间戳天然具有顺序递增性。

总结

  1. 乐观就是已不会冲突为预期,悲观就是会冲突为预期。
  2. 数据库是最基础的必备中间件,除了存储数据之外,还有很多其它功能也是支持的。乐观锁和悲观锁就可以,在数据库中以很低的成本、很便利的方式直接实现。
  3. 数据库自身也有分布式集群方案,使用数据库实现的锁也无缝的变成分布式锁了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 悲观锁
  • 乐观锁
  • 数据库悲观锁
  • 数据库乐观锁
  • 总结
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档