独占锁、共享锁、更新锁,乐观锁、悲观锁

转载自   独占锁、共享锁、更新锁,乐观锁、悲观锁

1、锁的两种分类方式

(1)从数据库系统的角度来看,锁分为以下三种类型:

 独占锁(Exclusive Lock)
      独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT、 UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁。但当对象上有其它锁存在时,无法对其加独占锁。独占锁一直到事务结束才能被释放。
 共享锁(Shared Lock)
      共享锁锁定的资源可以被其它用户读取,但其它用户不能修改它。在SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定。通常加共享锁的数据页被读取完毕后,共享锁就会立即被释放。
 更新锁(Update Lock)
      更新锁是为了防止死锁而设立的。当SQL Server 准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server 确定要进行更新数据操作时,它会自动将更新锁换为独占锁。但当对象上有其它锁存在时,无法对其作更新锁锁定。

(2)从程序员的角度看,锁分为以下两种类型:

悲观锁(Pessimistic Lock)
      悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

乐观锁(Optimistic Lock)
      相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
      而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

2、数据库中如何使用锁

首先从悲观锁开始说。在SqlServer等其余很多数据库中,数据的锁定通常采用页级锁的方式,也就是说对一张表内的数据是一种串行化的更新插入机制,在任何时间同一张表只会插1条数据,别的想插入的数据要等到这一条数据插完以后才能依次插入。带来的后果就是性能的降低,在多用户并发访问的时候,当对一张表进行频繁操作时,会发现响应效率很低,数据库经常处于一种假死状态。而Oracle用的是行级锁,只是对想锁定的数据才进行锁定,其余的数据不相干,所以在对Oracle表中并发插数据的时候,基本上不会有任何影响。

注:对于悲观锁是针对并发的可能性比较大,而一般在我们的应用中用乐观锁足以。

Oracle的悲观锁需要利用一条现有的连接,分成两种方式,从SQL语句的区别来看,就是一种是for update,一种是for update nowait的形式。

比如我们看一个例子。首先建立测试用的数据库表:

CREATE TABLE TEST(ID,NAME,LOCATION,VALUE,CONSTRAINT test_pk PRIMARY KEY(ID))AS SELECT deptno, dname, loc, 1 FROM scott.dept

这里我们利用了Oracle的Sample的scott用户的表,把数据copy到我们的test表中。

(1)for update 形式介绍

然后我们看一下for update锁定方式。我们执行如下的select for update语句:

select * from test where id = 10 for update

通过这条检索语句锁定以后,再开另外一个sql*plus窗口进行操作,再把上面这条sql语句执行一便,你会发现sqlplus好像死在那里了,好像检索不到数据的样子,但是也不返回任何结果,就属于卡在那里的感觉。这个时候是什么原因呢,就是一开始的第一个Session中的select for update语句把数据锁定住了。由于这里锁定的机制是wait的状态(只要不表示nowait那就是wait),所以第二个Session(也就是卡住的那个sql*plus)中当前这个检索就处于等待状态。当第一个session最后commit或者rollback之后,第二个session中的检索结果就是自动跳出来,并且也把数据锁定住。

不过如果你第二个session中你的检索语句如下所示:select * from test where id = 10,也就是没有for update这种锁定数据的语句的话,就不会造成阻塞了。

(2)for update nowait 形式介绍

另外一种情况,就是当数据库数据被锁定的时候,也就是执行刚才for update那条sql以后,我们在另外一个session中执行for update nowait后又是什么样呢。
比如如下的sql语句:

select * from test where id = 10 for update nowait

由于这条语句中是制定采用nowait方式来进行检索,所以当发现数据被别的session锁定中的时候,就会迅速返回ORA-00054错误,内容是资源正忙, 但指定以 NOWAIT 方式获取资源。所以在程序中我们可以采用nowait方式迅速判断当前数据是否被锁定中,如果锁定中的话,就要采取相应的业务措施进行处理。

那这里另外一个问题,就是当我们锁定住数据的时候,我们对数据进行更新和删除的话会是什么样呢。

比如同样,我们让第一个Session锁定住id=10的那条数据,我们在第二个session中执行如下语句:

update test set value=2 where id = 10

这个时候我们发现update语句就好像select for update语句一样也停住卡在这里,当你第一个session放开锁定以后update才能正常运行。当你update运行后,数据又被你update 语句锁定住了,这个时候只要你update后还没有commit,别的session照样不能对数据进行锁定更新等等。

总之,Oracle中的悲观锁就是利用Oracle的Connection对数据进行锁定。在Oracle中,用这种行级锁带来的性能损失是很小的,只是要注意程序逻辑,不要给你一不小心搞成死锁了就好。而且由于数据的及时锁定,在数据提交时候就不呼出现冲突,可以省去很多恼人的数据冲突处理。缺点就是你必须要始终有一条数据库连接,就是说在整个锁定到最后放开锁的过程中,你的数据库联接要始终保持住。

与悲观锁相对的,我们有了乐观锁。乐观锁一开始也说了,就是一开始假设不会造成数据冲突,在最后提交的时候再进行数据冲突检测。

在乐观锁中,我们有3种常用的做法来实现:

a. 在数据取得的时候把整个数据都copy到应用中,在进行提交的时候比对当前数据库中的数据和开始的时候更新前取得的数据。
    当发现两个数据一模一样以后,就表示没有冲突可以提交,否则则是并发冲突,需要去用业务逻辑进行解决。

b. 乐观锁的做法就是采用版本戳,这个在Hibernate中得到了使用。
    采用版本戳的话,首先需要在你有乐观锁的数据库table上建立一个新的column,比如为number型,当你数据每更新一次的时候,版本数就会往上增加1。
    比如同样有2个session同样对某条数据进行操作。两者都取到当前的数据的版本号为1,当第一个session进行数据更新后,在提交的时候查看到当前数据的版本还为1,和自己一开始取到的版本相同。就正式提交,然后把版本号增加1,这个时候当前数据的版本为2。当第二个session也更新了数据提交的时候,发现数据库中版本为2,和一开始这个session取到的版本号不一致,就知道别人更新过此条数据,这个时候再进行业务处理,比如整个Transaction都Rollback等等操作。
    在用版本戳的时候,可以在应用程序侧使用版本戳的验证,也可以在数据库侧采用Trigger(触发器)来进行验证。不过数据库的Trigger的性能开销还是比较的大,所以能在应用侧进行验证的话还是推荐不用Trigger。

c. 第三种做法和第二种做法有点类似,就是也新增一个Table的Column,不过这次这个column是采用timestamp型,存储数据最后更新的时间。
    在Oracle9i以后可以采用新的数据类型,也就是timestamp with time zone类型来做时间戳。这种Timestamp的数据精度在Oracle的时间类型中是最高的,精确到微秒(还没与到纳秒的级别),一般来说,加上数据库处理时间和人的思考动作时间,微秒级别是非常非常够了,其实只要精确到毫秒甚至秒都应该没有什么问题。
    和刚才的版本戳类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。如果不想把代码写在程序中或者由于别的原因无法把代码写在现有的程序中,也可以把这个时间戳乐观锁逻辑写在Trigger或者存储过程中。

 

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

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

相关文章

2019蓝桥杯省赛---java---B---2(不同子串)

题目描述 思路分析 看到不同,想到set去重 截取想到String.substring() 代码实现 package com.atguigu.TEST;import java.util.HashSet; import java.util.Set;class Main{public static void main(String[] args) {String target"0100110001010001";Se…

ASP.NET Core 程序发布到Linux(Centos7)爬坑实战

前言 前阶段弄了个Linux系统想倒腾倒腾.NET Core,结果看了下网上的资料,大部分都是过期的,走了不少弯路,不过还好,今下午总算捣鼓出来了。Linux命令太多了,唉。血的教训:安装一定要看官网的流程。 开始 首先…

关于Unsafe类的一点研究

转载自 关于Unsafe类的一点研究 Unsafe类是java中非常特别的一个类。它名字就叫做“不安全”,提供的操作可以直接读写内存、获得地址偏移值、锁定或释放线程。 通过正常途径是无法获得Unsafe实例的,首先它的构造方法是私有的,然后&#xf…

2019蓝桥杯省赛---java---B---3(数列求值)

题目描述 思路分析 此题类似于斐波那契数列,但是所求20190324项的最后四位数字,要是单纯按照斐波那契数列的思想求下去, 别说long类型,BigInteger类型都存不了这么大的数,然后我们发现,所求20190324项的最…

Visual Studio 2017 ASP.NET Core开发

Visual Studio 2017 ASP.NET Core开发,Visual Studio 2017 已经内置ASP.NET Core 开发工具. 在选择.NET Core 功能安装以后就可以进行ASP.NET Core开发。 新的ASP.NET Core项目为csproj ,打开之前的xproj项目,会提示单向升级,确认以后&#x…

2019蓝桥杯省赛---java---B---4(数的分解)

题目描述 思路分析 方案一&#xff1a;不定顺序&#xff1a;要除以6. 方案二&#xff1a;人为规定&#xff1a;a < b < c 代码实现 方案一 package com.atguigu.TEST;class Main{public static void main(String[] args) {int sum0;for (int i 1; i <1999; i) {f…

最通俗易懂的乐观锁与悲观锁原理及实现

转载自 最通俗易懂的乐观锁与悲观锁原理及实现 一、乐观锁 总是认为不会产生并发问题&#xff0c;每次去取数据的时候总认为不会有其他线程对数据进行修改&#xff0c;因此不会上锁&#xff0c;但是在更新时会判断其他线程在这之前有没有对数据进行修改&#xff0c;一般会使用…

mysql update field_mysql-更新表与另一个选择,但字段是SUM(someField)

基本上我有这样的事情&#xff1a;UPDATETableSETTable.col1 other_table.col1,FROMTableINNER JOINother_tableONTable.id other_table.id问题是我想用如下选择来更新col1&#xff1a;SELECT SUM(col1) FROM other_table WHERE Table.id other_table.id AND period > 20…

分布式一致性算法:Raft 算法

由于微信字数的限制&#xff0c;此处给出的并非全文&#xff0c;请拉到页面最下方点击阅读原文查看完整版。 Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法&#xff0c;而且 raft 算法比 Paxos 算法更易懂且更容易实现。本文对 raft 论文进行翻译&#xff0c;希望能有…

聚集索引、辅助索引、覆盖索引、联合索引

转载自 聚集索引、辅助索引、覆盖索引、联合索引 聚集索引&#xff08;Clustered Index&#xff09; 聚集索引就是按照每张表的主键构造一棵B树&#xff0c;同时叶子节点中存放的即为整张表的行记录数据。 举个例子&#xff0c;直观感受下聚集索引。 创建表t&#xff0c;…

2019蓝桥杯省赛---java---B---6(特别数的和)

题目描述 时间限制: 1.0s 内存限制: 512.0MB 本题总分&#xff1a;15 分【问题描述】小明对数位中含有 2、0、1、9 的数字很感兴趣&#xff08;不包括前导 0&#xff09;&#xff0c;在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40&#xff0c;共 28 个&#xff0c;他…

java谓词_在Java中谓词

我假设你正在谈论来自Guava的com.google.common.base.Predicate 。从API&#xff1a;确定给定input的true值或false值。 例如&#xff0c;一个RegexPredicate可能实现了Predicate &#xff0c;并且对任何匹配给定正则expression式的string返回true。这本质上是一个booleantesti…

.NET Core项目部署到linux(Centos7)

1.开篇说明 a 上篇博客简单的说明了一下 使用.NET Core开发的一个总结&#xff08;.NET Core跨平台&#xff1a;使用.NET Core开发一个初心源商城总括)&#xff0c;那么这篇博客我们就在上一篇博客的基础上对其代码进行部署&#xff0c;将其部署在Linux Centos7下。 b 这周周二…

2020蓝桥杯省赛---java---B---1(指数计算)

题目描述 代码实现 解法一 计算器 解法二 package com.atguigu.lanqiao;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input new Scanner(System.in);int a1,b1921,c7;for (int i 0; i < 2020; i) {aa*7;if(a>1…

java安装显示更改_java 安装与配置

到java.sun.com下载自解压安装包jdk-1_5_0_06-nb-4_1-linux-ml.bin安装&#xff1a;[rootRHEL4 JDK-1.5.0.06]# chmod x jdk-1_5_0_06-nb-4_1-linux-ml.bin[rootRHEL4 JDK-1.5.0.06]# ./jdk-1_5_0_06-nb-4_1-linux-ml.bin选择安装位置&#xff0c;NetBeans安装目录&#xff1a;…

dayjs​​​​​​​文档

转载自 dayjs API Dayjs 并没有改变或覆盖 Javascript 原生的 Date.prototype&#xff0c; 而是创造了一个全新的包含 Javascript Date 对象的 Dayjs的对象。 Dayjs 对象是不可变的, 所有的 API 操作都将返回一个新的 Dayjs 对象。 解析 当前时间时间字符串Unix 时间戳 (…

ASP.NET Core 优雅的在开发环境保存机密(User Secrets)

前言 在应用程序开发的过程中&#xff0c;有的时候需要在代码中保存一些机密的信息&#xff0c;比如加密密钥&#xff0c;字符串&#xff0c;或者是用户名密码等。通常的做法是保存到一个配置文件中&#xff0c;在以前我们会把他保存到web.config中&#xff0c;但是在ASP.NET C…

震惊,中国历朝历代疆域变迁视频【高清】

中国历代疆域指的是从古至今中国领土变化过程的历史&#xff0c;期间经过数千年的发展历程。 中国疆域自远古以来不断演进变化&#xff0c;从《尚书禹贡》九州开始直到唐朝极盛时疆域:被认为是中国疆域原型。至元朝时不仅统一中国&#xff0c;西藏地方从此正式纳入中国中央政府…

2020蓝桥杯省赛---java---B---2(指数计算)

题目描述 【问题描述】 小明设计了一种文章加密的方法&#xff1a;对于每个字母 c&#xff0c;将它变成某个另外的字符 Tc。下表给出了字符变换的规则&#xff1a; 例如&#xff0c;将字符串 YeRi 加密可得字符串 EaFn。 小明有一个随机的字符串&#xff0c;加密后为 EaF…

java项目新东方在线源码_[VIP源码]【S019】SSM框架开发智夫子在线考试系统项目源码 百度云盘...

java源码项目名称&#xff1a;SSM框架开发智夫子在线考试系统项目源码ssm项目源码5 y& C [0 w! J% F1 n8 z J百度网盘下载链接&#xff1a;4 B i* }. G4 }8 |7 l% G8 游客&#xff0c;如果您要查看本帖隐藏内容请->>回复[/hide]_* r Q0 _! W1 K4 Q" U6 F密码: …