漫话:如何给女朋友解释什么是乐观锁与悲观锁

戳蓝字“CSDN云计算”关注我们哦!

640?wx_fmt=jpeg

技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!

640?wx_fmt=jpeg

最近,我和女朋友商量好,我负责制定行程,她负责购买出行用品。相安无事,我正在各家比价中,不知道发生了什么,女朋友买买买竟然不高兴了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

并发控制

在《如何给女朋友解释什么是并发和并行》一文中我们介绍过并发和并行。当程序中可能出现并发的情况时,我们就需要通过一定的手段来保证在并发情况下数据的准确性,通过这种手段保证了当用户和其他用户一起操作时,所得到的结果和他单独操作时的祷告的结果是一样的。

这种手段就叫做并发控制。并发控制的目的是保证一个用户的工作不会对另一个用户的工作产生不合理的影响。

没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。

640?wx_fmt=jpeg
我们常说的并发控制,一般都和数据库管理系统(DBMS)有关,在DBMS中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。

640?wx_fmt=jpeg

640?wx_fmt=jpeg实现并发控制的主要手段大致可以分为乐观并发控制和悲观并发控制两种。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

在开始介绍之前要明确一下:无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。所以,不应该拿乐观锁、悲观锁和其他的数据库锁等进行对比。

悲观锁

当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。

这种借助数据库锁机制在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)。

之所以叫做悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。

640?wx_fmt=jpeg

但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,还会降低并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

乐观锁

乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

640?wx_fmt=jpeg

乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

悲观锁实现方式

悲观锁的实现,往往依靠数据库提供的锁机制。在数据库中,悲观锁的流程如下:

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

  • 如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。

  • 如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

  • 其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

我们拿比较常用的MySql Innodb引擎举例,来说明一下在SQL中如何使用悲观锁。

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。set autocommit=0;

我们举一个简单的例子,如淘宝下单过程中扣减库存的需求说明一下如何使用悲观锁:

//0.开始事务
begin
//1.查询出商品库存信息
select quantity from items where id=1 for update;
//2.修改商品库存为2
update items set quantity=2 where id = 1;
//3.提交事务
commit;

以上,在对id = 1的记录修改前,先通过for update的方式进行加锁,然后再进行修改。这就是比较典型的悲观锁策略。

如果以上修改库存的代码发生并发,同一时间只有一个线程可以开启事务并获得id=1的锁,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

上面我们提到,使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

乐观锁实现方式

使用乐观锁就不需要借助数据库的锁机制了。

乐观锁的概念中其实已经阐述了他的具体实现细节:主要就是两个步骤:冲突检测和数据更新。其实现方式有一种比较典型的就是Compare and Swap(CAS)。

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

比如前面的扣减库存问题,通过乐观锁可以实现如下:

//查询出商品库存信息,quantity = 3
select quantity from items where id=1
//修改商品库存2
update items set quantity=2 where id=1 and quantity = 3;

以上,我们在更新之前,先查询一下库存表中当前库存数(quantity),然后在做update的时候,以库存数作为一个修改条件。当我们提交更新的时候,判断数据库表对应记录的当前库存数与第一次取出来的库存数进行比对,如果数据库表当前库存数与第一次取出来的库存数相等,则予以更新,否则认为是过期数据。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

以上更新语句存在一个比较重要的问题,即传说中的ABA问题。

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

640?wx_fmt=jpeg

有一个比较好的办法可以解决ABA问题,那就是通过一个单独的可以顺序递增的version字段。改为以下方式即可:
//查询出商品信息,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问题,因为版本号只会增加不会减少。

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

以上SQL其实还是有一定的问题的,就是一旦发上高并发的时候,就只有一个线程可以修改成功,那么就会存在大量的失败。

对于像淘宝这样的电商网站,高并发是常有的事,总让用户感知到失败显然是不合理的。所以,还是要想办法减少乐观锁的粒度的。

有一条比较好的建议,可以减小乐观锁力度,最大程度的提升吞吐率,提高并发能力!如下:

//修改商品库存
update item 
set quantity=quantity - 1 
where id = 1 and quantity - 1 > 0

以上SQL语句中,如果用户下单数为1,则通过quantity - 1 > 0的方式进行乐观锁控制。

以上update语句,在执行过程中,会在一次原子操作中自己查询一遍quantity的值,并将其扣减掉1。

高并发环境下锁粒度把控是一门重要的学问,选择一个好的锁,在保证数据安全的情况下,可以大大提升吞吐率,进而提升性能。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

如何选择

在乐观锁与悲观锁的选择上面,主要看下两者的区别以及适用场景就可以了。

1、乐观锁并未真正加锁,效率高。一旦锁的粒度掌握不好,更新失败的概率就会比较高,容易发生业务失败。

2、悲观锁依赖数据库锁,效率低。更新失败的概率比较低。

随着互联网三高架构(高并发、高性能、高可用)的提出,悲观锁已经越来越少的被使用到生产环境中了,尤其是并发量比较大的业务场景。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=png


福利

扫描添加小编微信,备注“姓名+公司职位”,加入【云计算学习交流群】,和志同道合的朋友们共同打卡学习!


640?wx_fmt=jpeg


推荐阅读:

  • VMware竟然出了一款防火墙

  • OpenStack网络的下一步原来这么走 | 技术头条

  • 你的 AI 老师已上岗

  • 要成为年薪百万的技术大牛必经历这5个阶段, 收好这份超实用的技术进阶指南 | 技术头条

  • 助力 Android 抗衡 iOS,华为发布方舟编译器!

  • 程序员的黑砖窑,东南亚博彩骗局详解

  • 售价910元!周志华等人英文新书《演化学习》出炉!


640?wx_fmt=png真香,朕在看了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/524048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云计算之基,一文带你速懂虚拟化KVM和XEN

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!作者 :Pasca来源 :蛋蛋团正文 :共2022 字预计阅读时…

gradle下载及配置

下载:https://gradle.org/install/#manually 参考链接:https://www.cnblogs.com/linkstar/p/7899191.html 配置: 新建系统变量: GRADLE_HOME D:\Program Files\gradle-5.2.1编辑path,添加全局变量: ;%GRADLE_HOME%\…

qt自定义含有拖动功能的窗口在点击窗口的下拉列表时窗口移动

提要 自定义的弹出窗口,窗口可以实现按下鼠标拖动,鼠标释放停止拖动,窗口种含有子控件,下拉列表,在点击下拉列表时窗口移动。 解决方法 因为点击下拉列表的时候,触发了窗口的移动事件,所以添…

数字化转型2.0落地的正确姿势 | 人物志

戳蓝字“CSDN云计算”关注我们哦!人物志:观云、盘点、对话英雄。以云计算风云人物为核心,聚焦个人成长、技术创新、产业发展,还原真实与鲜活!如今,企业数字化转型已经进入2.0时代,数字化转型2.0…

新华三首发数字大脑计划;微软进军物联网领域?说好的三星折叠屏发布会,就这样不开了?Google 发布小型芯片 Jacquard...

关注并标星星CSDN云计算极客头条:速递、最新、绝对有料。这里有企业新动、这里有业界要闻,打起十二分精神,紧跟fashion你可以的!每周三次,打卡即read更快、更全了解泛云圈精彩newsgo go go 波音首席执行官“声明安全”…

OpenGL 图像白平衡色温

目录 一.OpenGL 图像白平衡色温 1.IOS Object-C 版本1.Windows OpenGL ES 版本2.Windows OpenGL 版本 二.OpenGL 图像白平衡色温 GLSL Shader三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenG…

Linux6、7 系列 安装、卸载mysql

Linux环境下载mysql: 点击链接: https://blog.csdn.net/weixin_40816738/article/details/90111456 一、安装环境依赖: yum install -y cmake make gcc gcc-c libaio ncurses ncurses-devel二、安装流程 1、软件解压2、添加系统mysql组和m…

Kafka精华问答 | Kafka的主要应用场景有哪些?​

Kafka是最初由Linkedin公司开发,具有高性能、持久化、多副本备份、横向扩展能力。今天,我们就看看看关于Kafka的精华问答吧。1:Q:什么是Kafka?A:Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写…

强推!十大顶级大数据可视化工具 | 程序员硬核评测

戳蓝字“CSDN云计算”关注我们哦!程序员硬核评测:客观、高效、不说软话。无论是技术质量、性能水平,还是工具筛选,一测便知!编译作者:风车云马前言Salesforce公司的一项调查显示:53%的员工要经常…

代码版本管理 GitLab介绍

一、前言 GitLab是利用 Ruby on Rails 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面进行访问公开的或者私人项目。 它拥有与 Github 类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的…

国内首款全国产固态硬盘控制芯片发布

4月22日,国科微与龙芯中科战略合作签约暨国内首款全国产固态硬盘控制芯片发布仪式在北京人民大会堂举行。双方将建立长期稳定的业务合作伙伴关系,携手打造关键信息基础设施国产化生态。作为首个战略合作成果,国科微发布全新的GK2302系列芯片&…

使用gitlab初次上传代码

提要 项目开发中需要使用gitlab来管理代码,将自己开发的模块上传到gitlab,第一次使用这个代码管理仓库,记录一下。 方法 1.首先注册gitlab的账号。这个在百度上搜一下gitlab的官网,进去后首页就是注册及登陆页面,没有账号的先注…

云数据库精华问答 | 现有数据库优化到云环境有什么好处​?

云数据库可以实现按需付费、按需扩展、高可用性以及存储整合等优势。我们就看看看关于云数据库的精华问答吧。1:Q:什么是云数据库?A:云数据库是指被优化或部署到一个虚拟计算环境中的数据库,可以实现按需付费、按需扩展、高可用性…

上传更新的代码到gitlab

提要 项目开发中已经初次上传代码到gitlab上,那么后面在本地修改了代码之后怎么上传,本文作以说明。 方法 首先说明一点,若你本地代码要上传的代码在你之前创建的本地仓库之外,那么你需要将要上传的代码拷贝到本地仓库中&#…

华为2019年第一季度业绩曝光;联想and谷歌加入英特尔新晋云计划;即特斯拉起火,蔚来ES8也维修起了火...

关注并标星星CSDN云计算极客头条:速递、最新、绝对有料。这里有企业新动、这里有业界要闻,打起十二分精神,紧跟fashion你可以的!每周三次,打卡即read更快、更全了解泛云圈精彩newsgo go go 亚马逊仓库(图片…

怎么从gitlab上下载别人的代码

提要 当需要从gitlab上下载别人的代码时,这里简述一下如何操作。 方法 按如下的步骤来实现: 1.在自己的电脑脑上新建一个空文件夹,文件夹的名称自己取。 2.在新建的文件夹上右键,选择git bash here菜单,弹出一个命令…

集群概述

一、什么是集群 1. 集群概念2.集群的特点3. 集群的两大能力4. 集群与分布式的区别 1. 集群概念 ①集群是一种计算机系统, 它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。②在某种意义上,他们可以被看作是一台计算机。集…

在这座智慧岛上 看华为的坚定与“野心”

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!在ICT这个江湖里,不乏拼搏向上的企业,但是耐得住性子、扛得住诱惑&#xf…

深入浅出Docker 镜像 | 技术头条

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!作为云计算的当红明星Docker 来势汹汹,它就像一场森林大火,烧到了我们中间…

一分钟弄懂什么是分布式和微服务

微服务是架构设计方式,分布式是系统部署方式,两者概念不同 一、微服务 1、简单来说微服务就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事。 2、这个服务可以单独部署运行,服务之间可以通过RPC来相互交互…