GaussDB常规锁简介

网友投稿 1329 2022-05-30

GaussDB 从轻量到重量定义了三种锁:

l  spinLock(自旋锁),系统级共享资源的封锁操作

l  LWLock(轻量锁):系统级共享资源的封锁操作,在系统运行期间,系统级的资源需要加锁,操作后,被释放。

l  RegularLock(常规锁/重量锁):用于并发保护用户表的数据。

常规锁按照被锁对象按照类型可以分为10种:relation,extend,page,tuple,transactionid,virtualxid,object,userlock,advisory,pg_locks视图中第一列locktype的取值就是这些。下面我们主要介绍常见的表锁(relation)和行锁(tuple)。

1 表锁

当对表进行DDL/DML 操作时,数据库会对表进行加锁操作,在事务结束时释放。常规锁按照粒度可以分为8个等级,各操作对应的锁以及相容性如下表所示:

当两个事务的锁产生冲突时,未拿到锁的线程会等锁,等锁超过系统设置参数lockwait_timeout(默认值20min)就会报错。报错信息会将持锁语句等信息打印出来,例如:

ERROR:  Lock wait timeout: thread 140354461361920 on node   coordinator1 waiting for AccessShareLock on relation 16655 of database 14764   after 1200.057 s

DETAIL:  blocked by hold lock thread 140354804238080,   statement , hold lockmode AccessExclusiveLock.

2 行锁

2.1 行锁模式

GaussDB不支持for key share和for no key update模式的行级锁,支持以下两种模式:

l  For share: 使用select for share语句时持有该模式锁,后台会对tuple加5级锁(ShareLock);

l  For update: 使用select for update, delete, update等操作时持有该模式的锁,后台会对tuple加7级锁(ExclusiveLock),根据上图中各级锁的相容性可知,并发更新同一条语句时会产生行锁冲突;

2.2 并发更新参数

当allow_concurrent_tuple_update=false时,并发更新同一条记录不会等锁,直接报错:

abort transaction due to concurrent   update

当allow_concurrent_tuple_update=true时,并发更新同一条记录会产生锁冲突。等锁超过系统设置参数update_lockwait_timeout(默认值2min)就会报错。报错信息可以分为几种,最重要的标志就是超时时间。

2.3 行锁加锁流程

行锁等到事务提交才会释放,其他事物如果等待这个行锁,必须等待这个事务锁释放。tuple锁可以保证多个修改事务加锁的顺序问题,原则是先来先拿锁,修改完tuple后,tuple锁会立即释放,而事务锁不会释放。假设有3个事务,A、B、C依次对同一行修改,均未提交:

Session A

Session  B

Session  C

begin;

update t set b=1;

set max_query_retry_times=0;

begin;

update t set b=2;

set update_lockwait_timeout='1s';

set max_query_retry_times=0;

begin;

update t set b=3;

此时A处于idle in transaction状态,B持有tuple锁但是等待A的事务锁,C等待B持有的tupe锁。如果B和C分别锁超时,那么超时报错信息如下所示:

C 先报错:

ERROR:    Lock wait timeout: thread 139728477222656 on node datanode3 waiting   for ExclusiveLock on tuple (0,1) of relation 33287 of database 14194 after   2000.096 ms

DETAIL:    blocked by hold lock thread 139728418502400, statement , hold lockmode ExclusiveLock.

B报错:

ERROR:    Lock wait timeout: thread 139728477222656 on node datanode3 waiting   for ShareLock on transaction 24858 after 120018.206 ms

DETAIL:    blocked by hold lock thread 139728691128064, statement < update t   set b=1; >, hold lockmode ExclusiveLock.

注释:

1. 如果此时A事务中又执行了一条select * from t;那么B的报错信息中statement就是