深入理解乐观锁与悲观锁
在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。
乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。
针对于不同的业务场景,应该选用不同的并发控制方式。所以,不要把乐观并发控制和悲观并发控制狭义的理解为DBMS中的概念,更不要把他们和数据中提供的锁机制(行锁、表锁、排他锁、共享锁)混为一谈。其实,在DBMS中,悲观锁正是利用数据库本身提供的锁机制来实现的。
下面来分别学习一下悲观锁和乐观锁。
悲观锁
在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。
悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。
悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)
在数据库中,悲观锁的流程如下:
在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。
如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。
如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。
其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。
MySQL InnoDB中使用悲观锁
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
set autocommit=0;
1
2
3
4
5
6
7
8
9
10
|
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id= 1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values ( null , 1 );
//3.修改商品status为2
update t_goods set status= 2 ;
//4.提交事务
commit;/commit work;
|
上面的查询语句中,我们使用了select…for update
的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。
上面我们提到,使用
select…for update
会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。
优点与不足
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数
乐观锁
在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。
实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。
使用版本号实现乐观锁
使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。
1
2
3
4
5
6
7
|
1 .查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2 .根据商品信息生成订单
3 .修改商品status为 2
update t_goods
set status= 2 ,version=version+ 1
where id=#{id} and version=#{version};
|
优点与不足
乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。
原文链接:http://www.importnew.com/21037.html
转载于:https://www.cnblogs.com/Terry-Wu/p/8982005.html
深入理解乐观锁与悲观锁相关推荐
- [初级]深入理解乐观锁与悲观锁
2019独角兽企业重金招聘Python工程师标准>>> 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔 ...
- mysql乐观锁与事务_[数据库事务与锁]详解七: 深入理解乐观锁与悲观锁
注明: 本文转载自http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库 ...
- 深入理解乐观锁与悲观锁(实战)
在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 乐观并发控制(乐观锁)和悲观并发控制(悲 ...
- 乐观锁和悲观锁的简单理解
乐观锁和悲观锁的简单理解 一.悲观锁 每次读取数据时认为其他线程会修改这个数据,所以每次读的时候都会加锁,实现悲观锁需要使用数据库的锁机制 1.共享锁 2.排他锁 3.行锁 ① 共享锁 共享锁也称为S ...
- 一文彻底理解乐观锁与悲观锁
通过阅读本文可以获得什么 1.什么是乐观锁? 2.乐观锁实现方式都有什么? 3.乐观锁优缺点有哪些? 4.乐观锁适用场景? 5.什么是悲观锁? 6.悲观锁实现方式有哪几种? 7.悲观锁优缺点? 8.悲 ...
- 浅谈对于乐观锁和悲观锁的理解
今儿回忆了一下关于乐观锁和悲观锁的知识,要唠唠这两个点,那先得知道什么是锁? 1.锁的定义:锁是一种互斥的机制,在多线程环境中实现对资源的协调与控制,凡是有资源被多线程共享,涉及到修改的情况就要考虑锁 ...
- 数据库---通俗理解乐观锁和悲观锁
mysql数据库和java中有关乐观锁和悲观锁的概念以及实现方式 在数据库的锁机制中,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时在存储数据库中同一数据时不破坏事物的隔离性和统一性 ...
- 乐观锁与悲观锁深入学习理解
乐观锁与悲观锁深入学习理解 一.乐观锁和悲观锁 悲观锁 乐观锁 二.两种锁的使用场景 悲观锁 乐观锁 三.乐观锁实现方式 四.乐观锁的缺点 五.总结 参考文献 一.乐观锁和悲观锁 乐观锁和悲观锁并不是 ...
- 乐观锁和悲观锁的理解及如何实现,乐观锁的实现方式。看完你就明白了!
文章目录 前言 面试回答话术: 乐观锁的实现方式: CAS缺点: 悲观锁和乐观锁 2.1.悲观锁 2.2.乐观锁 前言 在了解悲观锁和乐观锁之前,我们先了解一下什么是锁,为什么要用到锁? 技术来源于生 ...
最新文章
- 为什么手机升级系统反应慢了_win7系统鼠标右键刷新反应慢原因【解决方法】...
- 【基础】-设置VS2015开发环境
- IBASE deletion timestamp verification
- 使用Kubespray部署生产可用的Kubernetes集群(1.11.2)
- 有意思的select~
- 好看的简图动态背景图床源码 多接口聚合图床
- ECharts 入门真的很简单
- 利用EfficientNet-B5从眼底摄影检测糖尿病视网膜病变的严重程度
- python画圆形螺旋线_中秋节到了,送你一个Python做的Crossin牌“月饼”
- [转载]仿射变换(Affine Transformation)
- 2022年GPS广播星历精密星历如何下载
- 使用SCI-HUB下载论文
- 遍历文件夹下的所有文件(os.listdir())
- 原来使用 Pandas 绘制图表也这么惊艳!
- C++ 仓库管理系统 控制台
- 鼓励师加成太刺激了,鼻血喷了半斤,代码不一会儿就写完了...
- 学习vue3组件事件时,思维发散(溜号)的感悟
- Java实现替换Word中文本
- 揭秘linux启动过程
- React.createRef()的使用