达梦锁机制

锁机制

1.如何保证事务的隔离性

为了保证隔离性,一种方式是所有事务串行执行,让事务之间不互相干扰。但是串行执行效率非常低,为了增大吞吐,减小响应时间,数据库通常允许多个事务同时执行。因此并发控制需要保证:事务并发执行的效果,与事务串行执行的效果完全相同,以达到隔离性的要求。

数据库系统的锁管理器模块,专门负责给访问对象加锁和释放锁,保证只有持有锁的事务,才能操作相应的对象。锁可以分为两类:S-Lock和X-Lock,S-Lock是读请求使用的共享锁,X-Lock是写请求使用的排他锁。它们的相容性如下:操作同一个对象,只有两个读请求相互相容,可以同时执行,读写和写写操作都会因为锁冲突而串行执行,相容性很差。相容矩阵如下。

已加    待加

S

X

S

Y

N

X

N

N

2.意向锁的引入

如果只有行锁,那么事务要更新一亿条记录,需要获取一亿个行锁,将占用大量的内存资源。我们知道锁是用来保护数据库内部访问对象的,这些对象根据大小可能是:属性(Attribute)、记录(Tuple)、页面(Page)、表(Table),相应的锁可分为行锁、页面锁、表锁。对于事务来讲,获得最少量的锁当然是最好的,比如更新一亿条记录,或许加一个表锁就足够了。

层次越高的锁(如表锁),可以有效减少对资源的占用,显著减少锁检查的次数,但会严重限制并发。层次越低的锁(如行锁),有利于并发执行,但在事务请求对象多的情况下,需要大量的锁检查。数据库系统为了解决高层次锁限制并发的问题,引入了意向(Intention)锁的概念:

Intention-Shared (IS):表明其内部一个或多个对象被S-Lock保护,例如某表加IS,表中至少一行被S-Lock保护。

• Intention-Exclusive (IX):表明其内部一个或多个对象被X-Lock保护。例如某表加IX,表中至少一行被X-Lock保护。

• Shared+Intention-Exclusive (SIX):表明内部至少一个对象被X-Lock保护,并且自身被S-Lock保护。例如某个操作要全表扫描,并更改表中几行,可以给表加SIX。

意向锁的好处在于:当表加了IX,意味着表中有行正在修改。

1)这时对表发起DDL操作,需要请求表的X锁,那么看到表持有IX就直接等待了,而不用逐个检查表内的行是否持有行锁,有效减少了检查开销

2)这时有别的读写事务过来,由于表加的是IX而非X,并不会阻止对行的读写请求(先在表上加IX,再去记录上加S/X),事务如果没有涉及已经加了X锁的行,则可以正常执行,增大了系统的并发度

3.达梦数据库锁介绍

3.1锁的相关特性

拥有者:事务

作用:配合多版本并发控制(MVCC) ,保护数据一致 性,防止并发事务修改同一数据。

生命周期:一般事务结束时释放锁。

3.2锁模式分类

锁分类

说明

语法

共享锁(S)

读取操作创建的锁

LOCK TABLE tablename IN SHARE MODE;

排它锁(X)

用于写操作,以独占的方式访问对象,不允许任何其他事务访问被封锁对象;

LOCK TABLE tablename IN EXCLUSIVE MODE;

意向锁

共享意向锁(IS)

一般在只读访问对象时使用

LOCK TABLE tablename IN INTENT SHARE MODE;

共享排它锁(IX)

一般在修改对象数据时使用

LOCK TABLE tablename IN INTENT EXCLUSIVE MODE;

共享锁

会话1

会话2

LOCK TABLE t3 IN SHARE MODE;

update t3 set c2=3;

 

select * from t3;

 

可以看到上了共享锁后,其他会话允许查询,但是不允许修改。

排它锁

会话1

会话2

 lock table t3 in exclusive mode;

select * from t3;

 

update t3 set c2=3;

 

可以看到加了排它锁后,其他会话不允许查询,修改。

从上面可以看到,共享锁和排它锁相容性很差,意向锁是解决共享锁和排他锁相容性差的问题。

3.3锁相容矩阵

已加    待加

IS

IX

S

X

IS

Y

Y

Y

N

IX

Y

Y

N

N

S

Y

N

Y

N

X

N

N

N

N

3.4锁类型

按照封锁对象的不同,锁可以分为 TID 锁(事务锁)和 对象锁。

3.4.1 TID锁

TID锁以事务号为封锁对象,为每个活动事务生成一把 TID 锁,代替了其他数据库行锁的功能,防止多个事务同时修改同一行记录。

每个事务启动时创建一把独占的TID锁,锁模式为X锁 ,并持有到事务结束。

DM 实现的是行级多版本,每一行记录隐含一个 TID 字段,用于事务可见性判断。

执行 INSERT、DELETE、UPDATE 操作时,设置事务号到 TID 字段。这相当于隐式地对记录上了一把 TID 锁,INSERT、DELETE、UPDATE 操作不再需要额外的行锁,避免了大量行锁对系统资源的消耗。只有多个事务同时修改同一行记录时,才会产生新的 TID 锁。例如,当事务 T1(事务号为 TID1)试图修改某行数据,而该行数据正在被另一个事务 T2(事务号为 TID2)修改,此时事务 T1 会生成一个新的 TID 锁,其锁对象为事务号 TID2,而非事务 T2。

同时多版本写不阻塞读的特性,SELECT 操作已经消除了行锁,因此 DM 中不再有行锁的概念。

会话1

会话2

update t3 set c2=4 where c1=1;

select * from v$lock where 

(table_id=1079 or table_id=-1) and ign_flag=0

 

update t3 set c2=4 where c1=1;

select * from v$lock where 

(table_id=1079 or table_id=-1) and ign_flag=0

 

当会话1执行更新语句后,可以看到获取了两个锁,一个是IX对象锁,一个是X事务锁。

当会话2执行更新语句后,首先需要获取一个IX对象锁,很显然是可以获取的。还需要获取一个S事务锁,其锁对象是tid为52642的事务,锁记录对应的表是t3,但是被阻塞了。

会话1

会话2

update t3 set c2=4 where c1=1;

select * from v$lock where 

(table_id=1079 or table_id=-1) and ign_flag=0

 

 delete from t3;

select * from v$lock where 

(table_id=1079 or table_id=-1) and ign_flag=0

 

当会话2执行更新语句后,需要获取一个X事务锁,其锁对象是tid为52665的事务,锁记录对应的表是t3,但是被阻塞了。

3.4.2对象锁

对象锁是DM新引入的一种锁,通过统一的对象ID进行封锁,将对数据字典的封锁和表锁合并为对象锁,以达到减少封锁冲突、提升系统并发性能的目的。

3.4.2.1数据字典锁

用来保护数据字典对象的并发访问,解决 DDL 并发和 DDL/DML 并发问题,防止多个事务同时修改同一个对象的字典定义,确保对同一个对象的 DDL操作是串行执行的。并防止一个事务在修改字典定义的同时,另外一个事务修改对应表的数据。

多粒度分层上锁,如下图

 

数据字典锁的相关说明:

1)字典的上锁和解锁操作在执行计划的准备阶段执行阶段各自进行。

2)根节点必须首先加锁,仅当持有父对象的锁时,才可以对子对象上锁。

3)DDL语句会转成对相应系统表的DML操作语句,系统会拼接 SF_LOCK_DICT等内部SQL上锁函数语句插入到DML语句前。

4)INI参数DDL_WAIT_TIME决定DDL语句锁等待的超时时间 10秒,为0会一直等待。

字典锁举例

对象

DDL操作

封锁对象

数据库

表空间

模式

表/引用表/子表

create

IS

S

S

X/X/-

alter

IS

IX

S

X/IX/-

drop

IS

IX

S

X/IX/-

truncate

IS

IX

S

X/IX/X

3.4.2.2表锁

用来保护表数据的完整性,防止多个事务同时采用批量方式插入、更新一张表,防止向正在使用 FAST LOADER 工具装载数据的表中插入数据等,保证这些优化后数据操作的正确性。此外,表锁还有一个作用,避免对存在未提交修改的表执行 ALTER TABLE、TRUNCATE TABLE 操作。

为了实现与数据字典锁和表锁相同的封锁效果,从逻辑上将对象锁的封锁动作分为四

类:

a) 独占访问(EXCLUSIVE ACCESS),不允许其他事务修改对象,不允许其他事务访问对象,使用 X 方式封锁

b) 独占修改(EXCLUSIVE MODIFY),不允许其他事务修改对象,允许其他事务共享访问对象,使用 S + IX 方式封锁

c) 共享修改(SHARE MODIFY),允许其他事务共享修改对象,允许其他事务共享访问对象,使用 IX 方式封锁

d) 共享访问(SHARE ACCESS),允许其他事务共享修改对象,允许其他事务共享访问对象,使用 IS 方式封锁

其实从基本的锁类型(S、X)与意向锁类型(IS、IX)之间还可以组合出新的锁类型,理论上可以组合出4种,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不难看出,实际上只有S+IX有新的意义,其它三种组合都没有使锁的强度得到提高(即:S+IS=S,X+IS=X,X+IX=X)。

3.4.3隐式上锁

在执行SELECT、INSERT、DELETE、UPDATE等DML语句时 ,隐式上意向锁。 查询上IS锁;插入、删除和更新行存储表上IX锁,列存储表上X锁。

3.4.4显示上锁

用户可以根据自己的需要显式的对表对象进行封锁。显式锁定表的语法如下:

LOCK TABLE <table_name> IN <lock_mode> MODE [NOWAIT];

lock_mode 是锁定的模式,可以选择的模式有 INTENT SHARE(意向共享)、INTENT

EXCLUSIVE(意向排他)、SHARE(共享)和 EXCLUSIVE(排他),其含义分别如下:

意向共享:不允许其他事务独占修改该表。意向共享锁定后,不同事务可以同时增、删、改、查该表的数据,也支持在该表上创建索引,但不支持修改该表的定义;

意向排他:不允许其他事务独占访问和独占修改该表。被意向排他后,不同事务可以同时增、删、改、查该表的数据,不支持在该表上创建索引,也不支持修改该表定义;

共享:只允许其他事务共享访问该表,仅允许其他事务查询表中的数据,但不允许增、删、改该表的数据;

排他:以独占访问方式锁定整个表,不允许其他事务访问该表,是封锁力度最大的一种封锁方式。

当使用 NOWAIT 时,若不能立即上锁成功则立刻返回报错信息,不再等待。

当表获取IX锁后,无法创建索引

LOCK TABLE t3 IN EXCLUSIVE MODE;

select * from v$lock where (table_id=1079 or table_id=-1) and ign_flag=0

 

--不允许创建索引

create index idx1 on t3(c1);

等待10s后,直接报锁超时。这个时间是由dm.ini中DDL_WAIT_TIME参数决定的,默认10秒。另外超时后会释放锁。

 

因为update,insert,delete都会给表上IX锁,所以如果一个事务在执行这些操作,其他事务也是不允许创建索引的。

会话1

会话2

update t3 set c1=2;

create index idx1 on t3(c1);

 

查询

select * from t3;

select * from v$lock where table_id=1079;

 

--可以看到,在t3表上加了一个IS对象锁

insert into t3 values(5,5);

select * from v$lock where table_id=1079 or table_id=-1;

 

--可以看到在t3表上加了一个IX对象锁和一个tid X锁。

--当事务结束后,再次查看,可以看到IS,IX锁还未释放

 

3.5 阻塞与死锁

3.5.1阻塞

阻塞和死锁是会与并发事务一起发生的两个事件,它们都与锁相关。

当一个事务正在占用某个资源的锁,此时另一个事务正在请求这个资源上与第一个锁相冲突的锁类型时 ,就会发生阻塞。被阻塞的事务将一直挂起,直到持有锁的事务放弃锁定的资源为止。

3.5.2死锁

死锁与阻塞的不同之处在于死锁包括两个或者多个已阻塞事务,它们之间形成了等待环,每个都等待其他事务释放锁。例如事务 1 给表 T1 上了排他锁,第二个事务给表 T2 上了排他锁 ,此时事务 1 请求 T2 的排它锁,就会处于等待状态被阻塞。 若此时 T2 再请求表 T1 的排他锁,则T2 也处于阻塞状态。此时 这两个事务发生死锁,数据库会选择牺牲掉其中一个事务。

死锁

会话1

会话2

update test set c2='Jack2' where c1=1;

update test set c2='Lily2' where c1=2;

update test set c2='Lily2' where c1=2;

 

update test set c2='Jack2' where c1=1;

 

产生锁需要满足的条件:

1)这两个操作来自不同事务

2)至少有一个是写操作

3)操作对象相同

3.5.2阻塞与死锁的查看

阻塞可以简单的通过v$trawait视图来查看,改视图中有数据就说明有阻塞,没有数据就说明没有阻塞。

 select * from v$trxwait;

但是往往我们需要找出导致阻塞的具体会话以及执行的SQL,可以通过如下步骤:

查看锁

select * from V$LOCK where blocked=1;

 

根据事务id查看会话id

select * from v$trx where id = 54683;

 

查看会话id,找出sql

select * from v$sessions where sess_id=139767631124312;

 

当然也可以写成一个语句来查询

SELECT

        VTW.ID AS TRX_ID,

        VS.SESS_ID      ,

        VS.SQL_TEXT     ,

        VS.APPNAME      ,

        VS.CLNT_IP

FROM

        V$TRXWAIT VTW

LEFT JOIN V$TRX VT

ON VTW.ID=VT.ID

LEFT JOIN V$SESSIONS VS

ON VT.SESS_ID=VS.SESS_ID;

 

死锁因为数据库会自动处理,无法看到产生死锁的实时情况,可以通过V$DEADLOCK_HISTORY这个视图来了解死锁发生的情况。

select * from V$DEADLOCK_HISTORY;

 

3.6事务与锁相关视图

3.6.1 V$LOCK

显示活动的事务锁信息。

序号

数据类型

说明

1

ADDR

BIGINT

锁地址

2

TRX_ID

BIGINT

所属事务 ID

3

LTYPE

VARCHAR(10)

锁类型:TID 锁、对象锁

4

LMODE

CHAR(2)

锁模式:S 锁、X 锁、IX 锁、IS 锁

5

BLOCKED

INTEGER

是否阻塞

6

TABLE_ID  

INTEGER

对于对象锁,表示表对象或字典对象的 ID;对于 TID 锁,表示封锁记录对应的表 ID。-1 表示事务启动封锁自身的TID

7

ROW_IDX

BIGINT

锁封锁记录行信息。-1 表示事务启动封锁自身的 TID

8

TID

BIGINT

TID 锁对象事务 ID

9

IGN_FLAG

INTEGER

锁对象的 IGNORABLE 标记,INI参数 LOCK_DICT_OPT 开启时有效。

取值 0,表示锁正在使用中

取值 1,表示事务 TRX1 已经提交,但是锁资源未释放,TRX1 重新封锁时可以直接使用其他事务 TRX2 封锁相同对象时可以忽略此 IGN_FLAG=1 的锁LOCK1,但是要设置 LOCK1->IGN_FLAG=2,表示该锁 TRX1 不能直接使用,要释放后重新封锁

10

HLCK_EP

INTEGER

关联对象 HLCK 所属节点号。DSC 集群环境标识创建 HLCK 对象的节点号,默认为 255,单机无效

3.6.2 V$TRAWAIT

显示事务等待信息。

序号

数据类型

说明

1

ID

BIGINT

事务ID

2

WAIT_FOR_ID

BIGINT

所等待的事务ID

3

WAIT_TIME

INTEGER

当前等待时间

3.6.3 V$TRX

显示所有活动事务的信息。通过该视图可以查看所有系统中所有的事务以及相关信息,

如锁信息等。

序 号

数据类型

说明

1

ID

BIGINT

当前活动事务的ID号

2

NEXTID

BIGINT

下一个事务ID号

3

MIN_ACTIVE_ID

BIGINT

所有活动事务ID号最小者

4

STATUS

VARCHAR(20)

当前事务的状态

5

ISOLATION

INTEGER

隔离级。0:读未提交;1:读提交;2:可重复读;3:串 行化

6

READ_ONLY

CHAR

是否是一个只读事务

7

SESS_ID

BIGINT

当前事务的所在会话

8

SESS_SEQ

INTEGER

会话序列号,用来唯一标识会话

9

INS_CNT

INTEGER

插入回滚记录个数

10

DEL_CNT

INTEGER

删除回滚记录个数

11

UPD_CNT

INTEGER

更新回滚记录个数

12

UPD_INS_CNT

INTEGER

更新插入回滚记录个数

13

UREC_SEQNO

INTEGER

当前UNDO记录的递增序列号

14

WAITING

BIGINT

事务等待的锁

15

START_LSN

BIGINT

事务的起始 LSN

16

ROLLBACK_FLAG

INTEGER

是否在回滚

17

XID

VARBINARY(140)

 XA 事务唯一标识

3.6.4V$TRX_VIEW

显示当前事务可见的所有活动事务视图信息。根据达梦多版本规则,通过该视图可以查

询系统中自己所见的事务信息;可以通过与 v$trx 表的连接查询它所见事务的具体信息。

序号

数据类型

说明

1

SELF_ID

BIGINT

活动事务 ID

2

ACTIVE_ID

BIGINT

所见的事务活动事务 ID

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值