• Oracle 多粒度锁机制介绍


    Oracle 多粒度锁机制介绍

    根据保护对象的不同,Oracle数据库锁可以分为以下几大类:

    (1) DML lock(data locks,数据锁):用于保护数据的完整性;

    (2) DDL lock(dictionary locks,字典锁):用于保护数据库对象的结构(例如表、视图、索引的结构定义);

    (3) Internal locks 和latches(内部锁与闩):保护内部数据库结构;

    (4) Distributed locks(分布式锁):用于OPS(并行服务器)中;

    (5) PCM locks(并行高速缓存管理锁):用于OPS(并行服务器)中。

    在Oracle中最主要的锁是DML(也可称为data locks,数据锁)锁。从封锁粒度(封锁对象的大小)的角度看,Oracle DML锁共有两个层次,即行级锁和表级锁。

    3.1 Oracle的TX锁(行级锁、事务锁)

    许多对Oracle不太了解的技术人员可能会以为每一个TX锁代表一条被封锁的数据行,其实不然。TX的本义是Transaction(事务),当 一个事务第一次执行数据更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE语句进行查询时,它即获得一个TX(事务)锁,直至该事务结束(执行COMMIT或ROLLBACK操作)时,该锁才被释放。所以,一个TX 锁,可以对应多个被该事务锁定的数据行(在我们用的时候多是启动一个事务,然后SELECT… FOR UPDATE NOWAIT)。

    在Oracle的每行数据上,都有一个标志位来表示该行数据是否被锁定。Oracle不像DB2那样,建立一个链表来维护每一行被加锁的数据,这样 就大大减小了行级锁的维护开销,也在很大程度上避免了类似DB2使用行级锁时经常发生的锁数量不够而进行锁升级的情况。数据行上的锁标志一旦被置位,就表 明该行数据被加X锁,Oracle在数据行上没有S锁。

    3.2 TM锁(表级锁)

    3.2.1 意向锁的引出

    表是由行组成的,当我们向某个表加锁时,一方面需要检查该锁的申请是否与原有的表级锁相容;另一方面,还要检查该锁是否与表中的每一行上的锁相容。 比如一个事务要在一个表上加S锁,如果表中的一行已被另外的事务加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大, 系统的性能将会受到影响。为了解决这个问题,可以在表级引入新的锁类型来表示其所属行的加锁情况,这就引出了"意向锁"的概念。

    意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。如:对表中的任一行 加锁时,必须先对它所在的表加意向锁,然后再对该行加锁。这样一来,事务对表加锁时,就不再需要检查表中每行记录的锁标志位了,系统效率得以大大提高。

    3.2.2 意向锁的类型

    由两种基本的锁类型(S锁、X锁),可以自然地派生出两种意向锁:

    意向共享锁(Intent Share Lock,简称IS锁):如果要对一个数据库对象加S锁,首先要对其上级结点加IS锁,表示它的后裔结点拟(意向)加S锁;

    意向排它锁(Intent Exclusive Lock,简称IX锁):如果要对一个数据库对象加X锁,首先要对其上级结点加IX锁,表示它的后裔结点拟(意向)加X锁。

    另外,基本的锁类型(S、X)与意向锁类型(IS、IX)之间还可以组合出新的锁类型,理论上可以组合出4种, 即:S+IS,S+IX,X+IS,X+IX,但稍加分析不难看出,实际上只有S+IX有新的意义,其它三种组合都没有使锁的强度得到提高 (即:S+IS=S,X+IS=X,X+IX=X,这里的"="指锁的强度相同)。所谓锁的强度是指对其它锁的排斥程度。

    这样我们又可以引入一种新的锁的类型:

    共享意向排它锁(Shared Intent Exclusive Lock,简称SIX锁):如果对一个数据库对象加SIX锁,表示对它加S锁,再加IX锁,即SIX=S+IX。例如:事务对某个表加SIX锁,则表示该 事务要读整个表(所以要对该表加S锁),同时会更新个别行(所以要对该表加IX锁)。

    这样数据库对象上所加的锁类型就可能有5种:即S、X、IS、IX、SIX。

    具有意向锁的多粒度封锁方法中任意事务T要对一个数据库对象加锁,必须先对它的上层结点加意向锁。申请封锁时应按自上而下的次序进行;释放封锁时则 应按自下而上的次序进行;具有意向锁的多粒度封锁方法提高了系统的并发度,减少了加锁和解锁的开销。

    3.3 Oracle的TM锁(表级锁)

    Oracle的DML锁(数据锁)正是采用了上面提到的多粒度封锁方法,其行级锁虽然只有一种(即X锁),但其TM锁(表级锁)类型共有5种,分别 称为共享锁(S锁)、排它锁(X锁)、行级共享锁(RS锁)、行级排它锁(RX锁)、共享行级排它锁(SRX锁),与上面提到的S、X、IS、IX、 SIX相对应。需要注意的是,由于Oracle在行级只提供X锁,所以与RS锁(通过SELECT … FOR UPDATE语句获得)对应的行级锁也是X锁(但是该行数据实际上还没有被修改),这与理论上的IS锁是有区别的。 锁的兼容性是指当一个应用程序在表(行)上加上某种锁后,其他应用程序是否能够在表(行)上加上相应的锁,如果能够加上,说明这两种锁是兼容的,否则说明 这两种锁不兼容,不能对同一数据对象并发存取。

    下表为Oracle数据库TM锁的兼容矩阵(Y=Yes,表示兼容的请求; N=No,表示不兼容的请求;-表示没有加锁请求):


    表五:Oracle数据库TM锁的相容矩阵 

    一方面,当Oracle执行SELECT…FOR UPDATE、INSERT、UPDATE、DELETE等DML语句时,系统自动在所要操作的表上申请表级RS锁(SELECT…FOR UPDATE)或RX锁(INSERT、UPDATE、DELETE),当表级锁获得后,系统再自动申请TX锁,并将实际锁定的数据行的锁标志位置位(指 向该TX锁);另一方面,程序或操作人员也可以通过LOCK TABLE语句来指定获得某种类型的TM锁。下表是笔者总结了Oracle中各SQL语句产生TM锁的情况:


    表六:Oracle数据库TM锁小结 

    我们可以看到,通常的DML操作(SELECT…FOR UPDATE、INSERT、UPDATE、DELETE),在表级获得的只是意向锁(RS或RX),其真正的封锁粒度还是在行级;另外,Oracle数 据库的一个显著特点是,在缺省情况下,单纯地读数据(SELECT)并不加锁,Oracle通过回滚段(Rollback segment)来保证用户不读"脏"数据。这些都提高了系统的并发程度。

    由于意向锁及数据行上锁标志位的引入,减小了Oracle维护行级锁的开销,这些技术的应用使Oracle能够高效地处理高度并发的事务请求。

     

     

    Oracle 多粒度封锁机制的监控

    为了监控Oracle系统中锁的状况,我们需要对几个系统视图有所了解:

    5.1 v$lock视图

    v$lock视图列出当前系统持有的或正在申请的所有锁的情况,其主要字段说明如下:


    表七:v$lock视图主要字段说明 

    其中在TYPE字段的取值中,本文只关心TM、TX两种DML锁类型;

    5.2 v$locked_object视图

    v$locked_object视图列出当前系统中哪些对象正被锁定,其主要字段说明如下:


    表八:v$locked_object视图字段说明 

    5.3 Oracle锁监控脚本

    根据上述系统视图,可以编制脚本来监控数据库中锁的状况。

    5.3.1 showlock.sql

    第一个脚本showlock.sql,该脚本通过连接v$locked_object与all_objects两视图,显示哪些对象被哪些会话锁 住:

     

    /* showlock.sql */
    column o_name format a10
    column lock_type format a20
    column object_name format a15
    select rpad(oracle_username,10) o_name,session_id sid,
    decode(locked_mode,0,'None',1,'Null',2,'Row share',
    3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_type,
    object_name ,xidusn,xidslot,xidsqn
    from v$locked_object,all_objects
    where v$locked_object.object_id=all_objects.object_id;
    5.3.2	showalllock.sql
    

     

    第二个脚本showalllock.sql,该脚本主要显示当前所有TM、TX锁的信息;

     

    /* showalllock.sql */
    select sid,type,id1,id2,
    decode(lmode,0,'None',1,'Null',2,'Row share',
    3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive')
    lock_type,request,ctime,block
    from v$lock
    where TYPE IN('TX','TM');
  • 相关阅读:
    用对象模式实现QTP的远程调用
    Python 常用类库
    User32.dll 函数的相关方法整理
    python ConfigParser – 配置文件解析
    python 中的 __init__()解释
    Access to the database file is not allowed. [ File name = ***\DataBase.sdf
    在遗忘中成长
    在MVC3里如何关闭Form标签
    javascript 中写cookie
    .NET之死和观念的力量【】
  • 原文地址:https://www.cnblogs.com/yaoyangding/p/13155607.html
Copyright © 2020-2023  润新知