19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍|学习笔记

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 快速学习19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍

开发者学堂课程【PostgreSQL 快速入门19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/16/detail/78


19 PostgreSQL 锁类型,锁模式,锁冲突,死锁检测的介绍

 

内容介绍

一、 Postgre 的锁

二、 对象锁的模式

三、 行锁的模式

四、 串行的锁

五、 advisor rock

六、 死锁的检测和规避

 

一、Postgre 的锁

要讲一下 Postgre 的锁,前面讲了 Postgre 事务隔离级别和病情控制,首先来看一下锁的对象,也就是看哪些对象是可以加锁的,锁有一个视图可以去看,那么视图的含义是在 PostgreSQL  之中,然后可以找到手册,紧接着去找视图每一个列的解释。

image.png

当找到 Catalog 之后,那么这个锁里面就有一个锁的对象,被锁的对象是 relation ,这个对象对应的是pg class.oid ,那么这里面包含锁的类型,就是说这里锁的类型是指被锁的对象的类型,比如说它是一个表还是 x extended,还是说它是一个页或者是一个行,那么是一个行的时候,比如说查看到这个等于 tuple ,这时候表示说这条所记录的锁的是一个行,然后 transactionid 指的是锁的是一个数,这个是指的是锁的是一个虚拟事务,object 是一个对象,然后u lock跟advice lock指的是应用程序,这些内容后面也会讲的,那么这一些锁的对象其实在源代码的定义里面的某个地方,然后可以去看到这部分代码再去开一个窗口,这里面就定义这些锁的对象,从中可以找到在上面的锁的对象, LockType 指的是pg.locks Columns 的系统的视图里面,它对应的字段就是 LOCKTAG,那比如说 vhole relation 代表的是整个锁的 relation,比如说如果 relation 是一个表,那么就相当于整个表被锁,也就是说这条记录加锁的范围是整个relation ,然后这个 RELATION EXTEMD 对应的是 extend ,它表示被锁的是一个扩展 relation 的一个授权,比如说对某一个 relation 加载了 extended,它就表示 relation 也做一个表。它的空间不够要往里面插数据,那么它需要加一个 EXTEMD 的锁,然后它才能够去扩展对象,比如每次扩展一个配置,默认是8k那么当锁住之后能够给扩展8k的一个数据块。

image.png

这个是一个 extended lock,它是仅仅在 relation 要扩展的时候才会加这个锁,然后配置锁指的是 relation 的一个页面,比如说一个表的页面,前面在讲笔法控制和数格力级别的时候,当时讲了一些这个页面的锁,比如说那个锁的页面,这个页面是什么,这个锁的是什么,下面的 LOCKTAG PAGE 就是锁了一个物理行,比如说一个表锁了一行,那么这个信息指的是PAGE info 加 offsetnumber,比如说零号页面的第一行那么就是01,那上面这个是指的是relation的一个 page ,relation 的信息加上 Blocknumber就是组成了 page 的这个锁,然后后面的事务锁,那么它如果是锁的是一个事务,也就是说需要给这个事务加上锁,然后虚拟的事务锁的 id 是 uirtualTransactionID ,它指的是虚拟事务的一个数,还有 LOCKTAG_OBJECT 的锁指的是非数据库对象的锁,那么它包括 DB OID 、CLASS OID、 OBJECT OID 以及 SUBID ,就说这个锁里面就包含刚才的四部分的信息来定位到锁的是那个对象,我说的是哪个对象一块儿,那么最后一个 USERLOCK 指的是一些第三方老的贡献的代码,它提供了一些 user lock ,那现在可能已经不在使用了,那还有 ADUTSORY 指的是应用程序的 advisory user locks ,后面会讲到为什么会有这个 advisory。然后这些是锁的对象的类型,就是说被锁的对象的类型。比如说是整个表或者是一个扩展的权限,扩展一个所有的权限或者说的是一个页面或者是一个行或者是事务信息或者是对象,又或者是 ADVISOR或者 USERLOCK 。

image.png

 

二、对象锁的模式

接下来讲解的是锁的模式,就是说在这个对象上面加载的是什么模式的锁,然后这里它的源代码也是在这个地方。

image.png

它的锁的模式可以看到,在这个地方总共有八种模式,就说一个锁有八种模式,比如说 no lock 用一个数字常量0来表示,那么 AccessShareLock  需要用1来表示,它 select 的时候就会有这个锁模式,share lock 指的是创建索引指的是正常的,而非并行的。还有 modelBut allow low share 是指在 postgreSQL 的新版本里面新加的一个锁模式。还有下面这个是 Exc class lock 是指阻断以及 select date 这种操作的锁,还有最下面这个是最级别最大的一个锁是 ALTER table 或者 drop table 或者自定义的 table,那么它跟所有的锁都会发生冲突。那么后面会看到一个表,这个表里面就会说这一些各种锁模式之间是怎么发生冲突的。那这个表就表示锁模式的一个冲突表,这个叉叉就表示有冲突。就是说可以去参照这个表对应的这些操作,那就是说哪些操作跟哪些操作会发生冲突。

image.png

 

三、行锁的模式

前面说的是对象锁模式,那么接下来这个是行锁的模式,如果是一个行锁的话,比如说这种锁有四种锁模式,一个是 SELECT FOR ,它指的是行锁里面最低级别的一个锁,这种KEY的这种表那么被关联的时候可以去加载一个 SELECT FOR 的锁,那么这样加载这个锁之后 folding table 也不能去更新这个 KEY ,这也会发生一些冲突。然后 SELECT FOR SHARE 指的是更高级别的锁,就是说所有的整个的这条记录上面都加一个叫 FOR SHARE 。对于 FOR NO KEY 指的是更新的不是 KEY ,这个 KEY 指的就是folding table 。 FOR UPDATE 指的是整个的这条记录都加载一个 FOR ,虽然是加载这些记录上面,但是说如果更新的不是这个key,那么对于 folding table 不需要去加载对应的锁,也就是不会发生锁的冲突,因为在建 FOR NO KEY的时候,那如果用 on update 或者 on delete 这种操作,如果更新了这个被关联的表的 key 值,它其实是会影响到那些 folding table ,那么 for update指的是在对这一条记录的更新去加锁的时候,如果更新的不是这个 KEY 值,那么去加载这种锁就对于那种 folding table 不需要去加载对应的那一条记录那个 key 值的锁,所以这里相当于是行锁模式有四种,这四种模式使得行加锁的力度会比较小,力度越细,所带来的冲突就越细致,那比如说如果行上面只有一个 FOR UPDATE 锁,那相当于是 读和写就会犯冲突,所以说力度越细,就表示说冲突会越小,冲突的概率会越小。那看它的冲突, KEY SHARE 只跟 KEY UPDATE  这个方式发生冲突,KEY SHARE  不会跟其他任何一个发生冲突。

而 KEY UPDATE 是一个范围最广的一个锁,那么它会跟所有的锁都发生冲突。其次可以来看一下这个例子,这个是postgreSQL  这个版本增加了这个锁,9.3的版本里面已经有这个锁,就是说 FOR KEY SHARE 这种的锁,所以可以通过一个例子来演示一下,比如说创建一个a表,然后b1表的 AID  去关联这个a表的 AID ,它是一个主键。然后来创建这个b表,它的 BID 跟a表关联,然后注意这个版本是9.3的版本,所以它有这个。如果用其他版本去测试可能就看不到这个数,那么往a里面插入一条记录,这个 AID 是一,那么往b表里面插入一条记录是 reference,那么这个时候通过创建这个 pgrowlocks 可以去看到行锁这个 extension,比如说在会话里面往这个b表,b表是那个外键表往里面插入一条记录,去看一下这个行数就是a表上面有没有行数,看到a表上面加载了一个 forkey 需要的锁,虽然这里是b里面插入了一些记录

image.png

因为这个会话还没有结束,那就是说这个事务还没有结束,那么其实是b上面加载了一个锁,a上面也加载一个锁,但b这里面为什么看不到,因为b插入这条记录这边会话是看不到它的,看不到这个锁的,但是a表的这个锁是能够看到的,相当于a上面加了一个 forkey 这样一个锁,它就是最弱的一个锁,这就表示说往里面插入了这条id=1的这样一个记录,然后可以看到这个相当于是a上面的这一条记录就是01号这条记录,它对应的是1,那这里插入的这个 AID 也是1,就相当于是这个相关联的这条记录,它是上面要加载一个 for key share ,就表示说现在只是插进来了,这一条记录是不能把它删掉的,如果要删这条记录,相当于会有一个 KEY UPDATE 这样的操作或者是 Update 也是不允许的

image.png

比如说用 Update no wait,用这个 Select # from a where id =aid=1  for update nowait ,其实看到不能够在这上面去加载一个 for update ,因为它们有冲突,它上面有个 KEY SHARE。那对于老的版本,它其实这里就不是一个的 FOR KEY SHARE,它是一个FOR update,它的锁力度是更大的,FOR KEY SHARE 跟这种锁是不会冲突的,如果去更新了这条记录,更新的是 col1,它是允许更新的,比如说 update a set col1=1 where aid =1 ,这样是允许的,但是要去更新 AID 是不允许的,更新 AID 加的这个锁相当于更新了 KEY UPDATE 的锁,这样就会发生冲突了。但是可以在另外一个地方再来看 a 表,因为这个地方还没有提交,它还在处于一个等待状态,这个等待的时候看不到,只能看到零号404就第四条第四行,因为已经更新过了,零和四上面有一个 for key share 这样的锁

image.png

然后它锁的 locker 指的是324246853,它就是指的是事务 id ,它加载的 for key share 说明是6851加载的,这个6851的给它加载了一个 for key share,然后这个 share lock是下面所加载的,然后它正在等待那个锁,可以看到 where pid=7096,可以看到它需要的锁没有获得被授予,因为它还在等待。其次看到没有被授予的锁就是7096,然后对象是一个行,它是在等待需要的 lock,但是没有等到。然后在往后看一下这个例子,看到这个锁模式我 for key share 已经看到了,然后这个行的记录是1,然后更新a 表的丰键值无需等待,那么更新它的键值刚刚已经看到发生了等待。第二个场景 digoal update 这个 ID=2 vivid就相当于是第二个场景,先把这个场景也结束了,Begin update bid 相当于现在更新的是 b 表,b表上面去更新的时候会对a表加速,它加的又是一个 for key share,因为更新了这个 ID,它其实往上层就是说这个字段有其他的表,就是关联表外键表有在更新,所以这个 key 值现在不能变,如果变掉就会跟这个锁发生冲突,那么这个时候去看这个锁,因为它锁的是02号这条记录,现在记录是这样的,虽然把ID=2≠2变成2,那么这个时候更新a表的,同样是更新a表的 where aid=2这个是允许更新的,因为更新的跟它没有关系,更新的是另外一个key值。比如说再去查看这个 select # from,这个a表会发现它另外再加了一个叫 no key update,因为更新的是跟key没关系,这个key 是AID ,然后更新的不是这个Key的字段,所以又会加载一个叫做 key for no key update 这样一个表,那么会话b在更新a的时候是什么,刚刚已经看到了,它是一个 for no key update。然后在把第三个场景把它打开,再去同时更新这个 update  AID =1,这个已经变成第三个场景,再去看那其实 AID =1等于一,它其实也加载的是 no key update。其次可以看到select  ctid,# from aid =1,这个时候已经更新掉了,在这老的技术上面那只能在重新打开一个会话来看,select ctid ,* from a;可以看到四号这个记录就是更新了aid等于1的这条记录,它加的也是一个 no key update ,因为更新的是一个 no key,它不是一个 key,然后对于这个06号加载的是两个xid都对它有加锁,一个是 key share ,一个是 Nokey update ,这个 key share 是来自于这个会话,就是 update b1的时候带来的 for share 的这个数,然后 Update AID=1,然后把 AID =2这里更新的是也是 on key,所以说它上面也就加载了一个 Nokey update,在这上面通过pid给它加的,就是说哪个 pid  给它加的锁。这个都可以看到,通过这个行锁的插件都可以看到的,那么这就是一个行锁上面的四种锁模式,这四种锁模式使在有外键关联的时候,它所带来的冲突降低到了最小,

image.png

本来用其他的版本去做这种更新的时候,你会发现即使更新的不是这个key值,它也会发生锁冲突,因为以前的版本是没有新增这两种锁模式的。For share 和 no key update 这两种模式在以前是没有的,以前只有 for share 和 for update ,那么现在相当于是新增了这两种锁模式。

image.png

 

四、 串行的锁

接下来是一个串行的锁,串型锁在在上面讲事务隔离级别的时候已经演示过了,所以这块不用讲了。那么接下来讲一下锁的获取的方法,就是在 PostgreSQL 源代码里面。看它获得锁如何获得的,比如说要对 REATLON 加锁,比如说要对一个表加锁。那么调用这个红,这个红里面定义要加锁,这个锁的在那个数据库,然后它的lock tag的id是什么。然后 FIELD3FIELD4是固定是零的,然后这个锁类型告诉它是锁的一个 relation,这是一个默认的方法,它是通过调用这个红来告诉数据库要加载什么锁,那包括这个 relational expand page cook transaction,然后 visual transaction 还有这个 object 以及 advisory。这些前面讲的这种锁的对象都是通过这种红来去加锁的,那比如说接下来要讲的是这个 adviser lock,因为其他的这种锁这里就就不演示,所以就往后就重点讲一下 adviser lock。这个advice lock 会有这个 advicelock,因为前面讲多版本控制的时候,讲 postcard,它怎么样来实现并行控制,它其实就是说在同一个行上面会有多个版本,相当于生成多行,但是它其实对应的就是一条记录,多条记录相当于是虚拟出来的是一条记录,对外来说可能看到多个版本多行,比如说在并行的时候,又有写又有读的时候。那么跟事务隔离级别结合起来就能够看到有一些事务是那个老的版本,有些事务看到的是个新的版本,正因为这样相当于是在数据库当中一条记录会存在多个版本,然后当所有的这些对数据库修改的事务都提交之后,那么就最终其实对所有的用户来说,它其实都是一个版本。当然这跟事务隔离级别有关系,那所以一些被更新的就是那些老的版本都要从这个数据文件里面把它清掉,清掉之后这些空间才能被后面的这个数据插入来使用这些空间,也就 freestylep 里面要能够看到这些回收的垃圾数据,所以需要有这种 weekend 操作。也就是说 postcard 的这种多版本变化控制必然会带来一些垃圾数据,脏数据。就像 Oracle 里面 undo 表空间里面其实也是一些脏数据,是一些老版本的数据,那么这些老版本的数据其实也占用了一定的空间,就是说在 Oracle 里面,它也是对于这种垃圾数据也是要占用一定空间的,就是说Oracle 的这种多版本变化控制机制也会带来一些垃圾的空间,只是说它统一放在了那个回滚段的这个数据表空间里面,但 postgre SQL 相当于是都放在自己的数据文件里面,就说每个表都放在自己的数据文件里面,各种的版本都在自己的表空间,自己的文件里面,而不会说有一个统一的表空间来管理类似于回滚段的这种信息。也就是说会有垃圾回收,那么垃圾回收就带来了一个问题,当在数据库当中,比如说使用 rapid of read,或者是串行事务隔离级别启动了一个事务,然后这个事务假使它是一个很长的事务,这个长事务就会带来一个问题,比如说 pg dump 这种操作,Pg dumper 其实也是加载的这个 refiable read p dump 是一个逻辑备份的一个工具,就 POS read 逻辑备份的一个工具,这个逻辑备份为了备份一致性的数据,它也会去加载这个 repeatable read 这样一个数据事务隔离级别,然后它读到的数据都是同一个时间点的数据,就是说同一个事务看到事务镜像。那么如果是在普通的日常使用当中,使用了一个repeatable read这样一个事务隔离级别会发现数据隔离级别窄,后面就是前面产生的垃圾都没有办法回收。比如说会话a启动一个这样的数据事务隔离级别,然后接下来把某一个表删掉了,这个表其实说对于这个a会话来说其实不管删掉怎么样,还是能够查到这个记录的。那所以去回收它的时候,会发现它有一万行的是不可移除的版本。就说这1万行的记录版本是不能够把它从这个数据文件里面清掉的,只有当会话a结束之后,这部分空间才能被回收掉,这个就是跟隔离级别有关系,前面已经说了 repeatable read 或者是 three rights for 隔离级别,这个事务隔离级别里面所有的查询都会看到事务启动时候的状态,比如说这个事务启动的时候在会话B之前启动,那么这个事务相当于如果要来查这个 ISO test 这个表,你不管有没有把它的数据删掉,都能够看到这个原来的版本信息,也就是说这1万条记录的老版本的信息都还存在,都一定要看到的。如果把它清掉了,那不就看不到那个记录了,那不就是那这个隔离级别就相当于是被打破了,也就是说是 repeatable read 或者是 seriously 隔离级别就会带来这种问题,长时间开着这个事务后面所产生的一些垃圾都没有办法回收。这个问题就是说 advisor rock来解决的一个问题。

 

五、advisor rock

后面来看一下这个 advisor rock,对于这种长时间要占用一个事务来加锁,建议使用 otherwise As rock,这个advisory lock 里有两篇文章是以前写的,这是9.1增加的一个事务级别叫 advisory lock,那么9.3的当然也有这个事务隔离级别。然后来举一个例子它怎么来使用的,它是通过这些函数,就是说在SQL 语言当中它是通过这些函数来加锁,那比如说来看这个跟 rider rock 相关的这些锁,那么有这么一些锁

image.png

它有 shared rock,这种没有加X act的都是对整个会话加这种锁,那对于加了 X act 是表示说在这个事务当中加这个锁,当事务结束的时候,这些锁都会自动回收掉,那么这种只是在这个会话当中加这个锁,只有当这个会话退出的时候才会把这个锁给释放掉,那么这个 TRY 其实就是去尝试加这个锁,加载不成功就返回 force,加载成功返回去 cute,那对于上面这一些是相当于同步加锁如果没有加载成功就一直等待。

而对于这种 TRY 指的是没加载成功,就直接返回 force,也不会等待,那后面会有例子讲这个问题,比如说这样的应用场景,对于就是说在数据库当中存储了一些文件和 ID 的对应关系,那么应用程序可能要长时间持有这个锁,然后对文件进行修改,然后再释放这个锁。也就是说对同一个文件的修改必须要先持有锁,然后才能对这个文件去修改,这样避免同时有多个进程去修改同一个文件,那么要加这种锁,就需要先创建了这个测试表叫做 file info,比如说这里来创建这个表,这里面存储了路径信息,那往里面插入几条记录,这些都是测试用的,总共插三条记录进去,那接下来会话a去获得这个锁,就说现在连在这上面,现在是连在这上面然后要获得这个锁。Select 这是一个会话锁,然后 fine pass 是指这个文件的路径,然后围绕 ID 等于一,那么这个时候它相当于是获得了一个 ID 等于一的这样一个锁,其实它相当于执行了一个这样的操作,也就是说它的传送参数是一个 big in 的,这个 ID 是一,那么其他的会话要去加这个锁就必须要等待,比如说这里也要去加载这个锁,它就等在那里,那肯定把它退掉。如果你用 TRY 就直接返回 force,比如说没有加载成功,就比如说现在没有加载成功,那获得这个锁之后就可以去编辑这个文件了,因为其他的会话不能获得这个锁,所以在业务逻辑上没有获得这个锁,就不去编辑这个文件。当这个文件被编辑完了之后,在会话a里面比如说编辑这个文件编辑完了,然后要保留,保存完了之后这个锁就要释放掉,通过 select 进行释放,这个P对应的P加Y是 rock1,就比如说已经把它释放掉了。

image.png

那这个时候在会话B里面再去踹它,它就可以返回 true,就比如说已经获得了这个锁,那在a里要再去加载这个锁它就等待。就相当于现在已经被它加载去了,但如果是加载这个 ID 不一样的,比如说要修改第二个文件,修改第二个文件可以加载到这个锁,因为相当于是传入的这个参数是2,相当于这里执行了一把2。

image.png

如果多次执行这种锁,释放也是要多次释放,比如说这里释放一次是不够的,那这里再去 TRY 这个二,它也是一个false。你请求了几次锁就要释放几次,那比如说一直释放到它为 force 为止已经没有这个锁了,不需要再释放那么这个时候就可以加载

image.png

就相当于是 advervisary lock 是通过一个 big int 的一个参数来指定对于这个 ID 加载一个 ad y z lock,那么其他的会话就不能去加载了,那对于事务也是一样的,如果是说这个锁只是在事务当中生效,就用这个 p gl y z X act lock 这个函数去加载这个锁,那么这里加载的是会话级别,那么这个应用场景因为跟不需要长时间持有一个 MACC 的常规锁,持有的是一个 ed y z lock,那么这种的情况下去回收垃圾数据就不会出现那种像前面提到的这种问题,比如去回收垃圾的时候加载了这种锁,其实对垃圾回收是没有任何影响的,那么这里是讲到一个 advisory lock。

 

六、死锁的检测和规避

接下来讲一下死锁的检测和规避,死锁的产生其实很简单就是相互锁了,就说 a 会话锁了一个对象,然后 B 会话也锁了一个对象,然后接着 a 会话要去锁 B 会话锁住的那个对象,然后 B 话要去锁住 a 会话锁的对象,这指的是两个会话的一个死锁,那三个会话,四个会话之间也有一个死锁的产生,比如说 ABC,那么a 在等 B,B 在等 C,C 又在等 A,这种也会出现死锁,那么像这种两个会话的比较简单,看起来就很容易能够看到A在这个时候其实在等B,这里应该是 lock  tuple2waiting,然后这里 lock tuple1WAITING,这写法要注意。那么会话B其实是在等这个会话a以前所做的,这样就造成相互的一个等待,相互等待让postgreSQL能够自动的检测到死锁的相互等待的情况,那么死锁的检测时间间隔是默认是一秒钟,如果这个死锁检测的时间是太小,那么其实会带带来比较大的负面的影响。

比如说默认一毫秒就去检测一次这个锁是不是发生死锁,这个其实对数据库的性能影响是很大的,默认其实有一秒钟其实就差不多了,因为死锁这个东西出现的概率并不是太高,当然如果业务设计比较烂,那出现概率是可能是会很高的,那种就需要去那个业务逻辑层面要去修改,避免出现死锁的这种情况,那么死锁检测的算法可以通过一个源代码里面有介绍文件,可以去看死锁的检测算法是样子。这里面算法就整个讲了一下死锁是怎么检测的,然后死锁的检测时间间隔刚刚讲过了。就说默认是一秒钟,那么也就是说在等待一秒钟的时候肯定会触发。那么所等待超时的这个配置,触发死锁的检测算法,就是说等待了一秒钟,就超过了一秒钟之后就会触发这个死锁的检测算法,也就是刚刚提到这个文件里面描述的一些算法,因为死锁检测比较耗资源,所以这个时间视情况而定,就说默认一秒钟基本上不需要去修改,但可以把时间稍微改小一点。比如说500毫秒也是可以的,一秒钟也差不多了,那么 Postgre 跟 Oracle 死锁检测的例子是有一定的区别的,Postgre 跟 Oracle死锁检测有一定的区别。

image.png

举了一个例子,比如说这里三个事务,那A锁住了一个,这个是时间,那个是会话,就说在T1这个时间点。T是 Table 的意思, T1T2 T3,那A会话锁住T1这个表,B会话锁住T3这个表,C会话说T2,然后接下 waiting b,这里的 waiting waiting 是 complete successful field transaction dialogue detect,对 postgway 来说,最后一个等待的它是去触发死锁的,死锁检测的时候,它检测到是最后一个触发,最后一个等待的这个会话,然而对于 Oracle 来说,它可能就不太一样,来看一下死锁的被检测到的属于哪个会话,那么 Oracle,是随机检出,从后面实验来看,第一个启动了死锁事务,而 Postgre 事务发生在最后一个事务死锁,与 Oracle 刚好相反。那么从 PG 的 lock deadlock 的参数可以看出来 POSTGRADE 死锁检测并不是随机的,而是可预见,This is the amount of time, inmileseconds, to wait on a lock before checking to see if there is a deadlock condition,那么它肯定一秒钟之后才能检测出来,那么对于 Oracle 来说这是一个随机的,就是说随机的从实验来看,那么它是第一个启动的事务,第一个发生等待的,比如说a最开始等待,那么 Oraclea 就会认为可以回滚了,因为已经检测到死锁,然后死锁被检测到之后的处理上也有一个差别。Oracle 可以允许单个事务中的部分 SQL 执行成功,它不会 SQL 执行失败,当然这不是一个什么严重的缺陷,就是说它其实是在每一个 SQL 上面都有一个类似于一个 save point,它可以相当于是这一条 SQL 语句执行失败了,从上面一条执行成功的,这个可以往后再执行,相当于它相当于是回滚到了上面一个 save point,而 Postgre 其实也支持这种风格,也就是说对每一条 SQL 语句都自动加一个 save point,那么也是可以默认的,就是说它可以像Oracle 这样允许在整个事务当中有单个 SQL 执行失败,那么后面可以直接放弃掉执行失败的 SQL,后面还可以继续执行SQL。

那默认情况下是不允许的,默认情况下 postgre 相当于是如果有部分 SQL 执行失败,整个的事务必须回滚,这个是通过一个参数

image.png

比如说在 PGSOL 里有一个参数叫做 on either stop on other law back,就这两个 on error role back,它来定义这个事务是不是允许其中有一个失败,那默认是关掉的,如果你把它打开就会出现这种情况,比如说补丁一个,这个是要 shift。这里发生了一条错误的语句,它也是允许阻止。但是如果把它关掉,现在先把事务结束掉,把它关掉,那默认是关掉,再比如说触犯一个语法错误,它就不允许执行了,当前事务已经要 both 掉了,那对于这种把它打开的情况,是对每一个 SQL 语句,它相当于是都会帮你在 SQL 语句之前会有一个 save point,就如果失败就回到失败之前的那个 savepoint,就说 rollback t2,比如说 rollback to1,就相当于是每一个上面都有一个 save point 这样一个东西,那么 Oracle 的默认的风格就是说允许你相当于是都有一个 save point

image.png

也就相当于说 postgrare 里面把这个打开的这样一个风格,而 Postgre 默认是关闭的,这个两个模拟死锁场景和检测的结果

image.png

这个是 postgre,那么下面这个是 Oracle。

image.png

Oracle 相当于是第一个等待的事务检测到死锁,Postgre 最后一个等待的事务检测到死锁,这是一个测试场景。这三个会话,那比如说第一个会话是 ID 等于1的 test tb2test这个表,Update 这个更新 TEST2这个表,然后第三个会话又去更新 TEST1这个表,那么再第一个会话再去更新 TEST2这个表,然后B会话就更新 TEST1,它们已经发生等待,然后C会话去更新 test,那C会话在发生等待的时候就检测死锁,它们相互之间正在等待,告诉它会让用去查看详细的日志

image.png

那么B和A就相当于是可以提交的,但C已经帮你回滚掉了,这 commit 的时候直接直接 back。那么这是一个死锁的检测。那 Oracle 后面就没有全部写出来,Oracle 在实际设置当中是可以看到 Oracle 是在第一个等待的时候就检测到了这个失败的一个事务,那也就是说规避死锁跟那个业务逻辑有关系,比如说尽量不要去出现

image.png

比如说a会话锁了一个 UCID 等于1的,那B会话锁了一个 UCID 等于2的,那接下来a会话也要去锁一个会 ucd 等于2的,然后在B会话又要去锁一个 UCID 等于1的,这种就发生死锁,那么这种情况是需要在业务层面去规避这种情况,在数据库这个层面没有办法去做到不允许去做这种操作,肯定是没有办法去做的,它只能说通过这种死锁的检测,帮你检测出来有发生了死锁,那就帮你把最后那个在 postgre 里面是把最后那个等待帮你毙掉,那是这样一个情况。

那么 postgre 锁就介绍到这里,后面是一些练习,大家可以参照练习,比如说怎么验证锁的冲突这种,谢谢。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
2月前
|
DataWorks Java 关系型数据库
DataWorks常见问题之将预警信息发送至邮箱
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
|
8月前
|
关系型数据库 Go PostgreSQL
golang pgx自定义PostgreSQL类型
golang的pgx驱动提供了大约70种PostgreSQL类型支持,但还是有一些类型没有涵盖,本文介绍如何自己编写代码支持特殊的类型。
103 3
|
2月前
|
SQL 关系型数据库 数据库
实时计算 Flink版操作报错之使用SQL 将 PostgreSQL 的 date 类型字段转换为 TIMESTAMP 类型时遇到报错,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
1天前
|
存储 关系型数据库 MySQL
|
22天前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之离线同步任务中,把表数据同步到POLARDB,显示所有数据都是脏数据,报错信息:ERROR JobContainer - 运行scheduler 模式[local]出错.是什么原因
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
2月前
|
关系型数据库 数据库 索引
|
2月前
|
关系型数据库 Serverless 分布式数据库
【PolarDB 开源】PolarDB Serverless 模式:自动扩缩容与成本效益分析
【5月更文挑战第25天】PolarDB Serverless 提供自动扩缩容功能,适应动态工作负载,降低成本。在业务高峰期增加资源保障性能,低谷期减少资源实现成本优化。通过对比传统模式下的成本浪费,示例说明了Serverless如何节省开支。代码演示了连接与查询PolarDB Serverless数据库的基本操作。要充分利用该模式,需合理规划业务、监控性能并结合其他云服务。PolarDB Serverless是弹性、经济的数据库选择,未来将持续创新,助力企业高效发展。
380 1
|
2月前
|
分布式计算 DataWorks 关系型数据库
DataWorks产品使用合集之在使用 DataWorks 数据集成同步 PostgreSQL 数据库中的 Geometry 类型数据如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
37 0
|
2月前
|
分布式计算 关系型数据库 大数据
MaxCompute产品使用合集之怎么才可以将 PostgreSQL 中的 geometry 空间类型字段同步到 MaxCompute 或另一个 PostgreSQL 数据库
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
2月前
|
关系型数据库 Serverless 分布式数据库
PolarDB的Serverless能力与同类型产品的对比
【2月更文挑战第21天】PolarDB的Serverless能力与同类型产品的对比
33 2