当前位置:  数据库>oracle

Oracle中的锁(LOCK)机制详解

    来源: 互联网  发布时间:2017-06-24

    本文导语: 本文结合示例详细的介绍下Oracle中锁的机制。 使用锁的目的是什么 为了解决多用户环境下并发操作相同的资源而造成的错误修改数据的问题。单用户环境下不需要考虑锁,因为所有操作都是串行的。 要点 锁的分类异常复杂,en...

本文结合示例详细的介绍下Oracle中锁的机制。

使用锁的目的是什么

为了解决多用户环境下并发操作相同的资源而造成的错误修改数据的问题。单用户环境下不需要考虑锁,因为所有操作都是串行的。

要点

锁的分类异常复杂,enqueue、latch、mutex等,都是为了解决并发存在的,自己也有些混乱,所以也不过多解释了。下面列举一些对于lock的要点内容。

排他锁:

不允许相关的资源被共享。一个资源在一个时间点内只有一个事务能够获取该资源的排他锁,只有持有该锁的事务能够修改相关的资源,

其他想要获取锁的事务只能等待该事务因为commit或者rollback而释放排他锁。

共享锁:

允许相关的资源被共享。也就是说允许多个事务同时持有某个资源的共享锁。

对于一个dml操作,会对表以及行加锁,也就是v$lock中的TM锁和TX锁。

行级锁基本原理:

行级锁的信息是置于数据块中的,如果要修改某一条记录的值,其实就是在访问相应的block,并且分配一个ITL,然后通过rowid访问

rowpiece header ,如果第二个字节lock byte(lock byte只占用1个字节,最大值为255,这也是为什么maxtrans最大为255)为0,则将其改为分配的ITL slot number。另外一个事务如果也想要修改数据,就会发现lock byte不为0,如果第一个事务还没有结束,则第二个事务进入enqueue等待,也就是transaction enqueue。

关于transaction enqueue有一个很有趣的例子,事务不一定是按照时间的先后顺序进行的。

具体地址在:

http://docs.oracle.com/cd/E11882_01/server.112/e25789/transact.htm#autoId12

对于Table lock来说可以分为以下几种类型:

1. Row Share (RS|SS)

2. Row Exclusive Table Lock (RX|SX)

3. Share Table Lock (S)

4. Share Row Exclusive Table Lock (SRX|SSX)

5. Exclusive Table Lock (X)

以下是v$lock.LMODE字段中的数字对应的锁类型

LMODE(Lockmode in which the session holds the lock):

0 -none

1 -null (NULL)

2 -row-S (SS)

3 -row-X (SX)

4 -share (S)

5 -S/Row-X (SSX)

6 -exclusive (X)

为了更好的开展下面的内容,这里列举一下各种TM锁类型的兼容情况。

详细验证情况会在4中给出。

表1

 

RS|SS

RX|SX

S

SRX|SSX

X

RS|SS

×

RX|SX

×

×

×

S

×

×

×

SRX|SSX

×

×

×

×

X

×

×

×

×

×

顺便引用一下经典内容:

只有被修改时,行才会被锁定。

当一条语句修改了一条记录,只有这条记录上被锁定,在Oracle数据库中不存在锁升级。

当某行被修改时,它将阻塞别人对它的修改。

当一个事务修改一行时,将在这个行上加上行锁(TX),用于阻止其它事务对相同行的修改。

读永远不会阻止写。

读不会阻塞写,但有唯一的一个例外,就是select ...for update。

写永远不会阻塞读。

当一行被修改后,Oracle通过回滚段提供给数据的一致性读

1.分别模拟insert,update和delete造成阻塞 一个更新语句的简单描述

当我们更新一个表的记录的时候,会有两种锁产生,一种是DML锁(TM)也可以称作table lock 还有一种事务锁(TX)也可以称作行锁

在v$lock中可以查看到。

例如下面的例子当中:

_dexter@FAKE>desc tun2_tab

 Name                                                             Null?    Type

 ------------------------------------------------------------------------- --------------------------------------------

 ID                                                                        NUMBER(38)

_dexter@FAKE>update tun2_tab set id =2 ;

2 rowsupdated.

_dexter@FAKE>select sid , type , lmode , request , block

from v$lock

where sid =(select sid from v$mystat where rownuminsert /*+ append_values */ into tun2_tab values (1) ;

1 rowcreated.

_dexter@FAKE>select sid , type , lmode , request , block from v$lock where sid = (select sidfrom v$mystat where rownumupdate tun2_tab set id=3 ;

waiting...

看一下锁的情况:

_sys@FAKE>select sid , type , id1 , lmode , request , block

  2   from v$lock l

  3  where sid in (select session_id from v$locked_object)

  4    and type in ('TM', 'TX')

  5  order by 1 ;

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        22 TM        82618          6          0          1        --session1 包含了表6级锁,它正在阻塞其他的事务

        22 TX      524296          6          0          0

        24 TM        82618          0          3          0        --session2 它正在请求表的3级锁。

 

Session1

Session2

Description

T1

insert /*+ append_values */ into tun2_tab values (1) ;

 

直接路径加载会对表加6级排他锁

T2

 

update tun2_tab set id=3 ;

waiting…

update需要对表加3级共享锁,因为互斥,session2陷入阻塞状态

所以在直接路径加载的时候会对表加6级锁,阻塞其他事务对表加任意类型锁的操作。

(sqlldr 并行+直接路径加载的时候会加4级锁)

因为主键|唯一键引发的阻塞

_dexter@FAKE>alter table tun2_tab add primary key (id) ;

Table altered.

session1 session_id=22:

_dexter@FAKE>insert into tun2_tab values (1) ;

1 rowcreated.

session2 session_id=24:

_dexter@FAKE>insert into tun2_tab values (1) ;

waiting...

lockstatus :

_sys@FAKE>select sid , type , id1 , lmode , request , block

  2   from v$lock l

  3  where sid in (select session_id from v$locked_object)

  4    and type in ('TM', 'TX')

  5  order by 1 ;

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        22 TM        82618          3          0          0

        22 TX      196635          6          0          1       

        24 TX        65548          6          0          0

        24 TM        82618          3          0          0

        24 TX      196635          0          4          0

_sys@FAKE>select sid,seq#,event from v$session_wait where sid= 24 ;

      SID      SEQ# EVENT

-------------------- -----------------------------------------------

        24        104 enq: TX - row lock contention

这里发生了row lock等待事件。

可以看到

因为在拥有primary key 列上插入了相同的值,第二个session除了持有自己本事务的6级排他锁之外,还在请求一个4级共享锁。这里发生了阻塞。如果第一个session 提交 。

第二个session会报错。

_dexter@FAKE>insert into tun2_tab values (1) ;

insert intotun2_tab values (1)

*

ERROR atline 1:

ORA-00001:unique constraint (DEXTER.SYS_C0014094) violated

 

Session1

Session2

Description

T1

insert into tun2_tab values (1) ;

 

session1插入数据这里涉及到了主键|唯一键

T2

 

insert into tun2_tab values (1) ;

waiting …

session2插入相同的记录,会发生阻塞,因为session1的操作是悬而未决的状态,session2中的事务能否执行取决于session1中的事务是回滚还是提交

T3

commit

 

session 1 中的事务提交

T4

 

Raise error:

ORA-00001: unique constraint (DEXTER.SYS_C0014094) violated

  Update阻塞

这一部分的阻塞比较简单,只要发生update操作,就会对已有的行加6级排他锁,表上加3级共享锁。

_dexter@FAKE>select * from tun2_tab ;

        ID NAME

--------------------------------------------------

        1 NN

        2 NN

        3 NN

session1 session_id=22:

_dexter@FAKE>update tun2_tab set name = 'DEXTER' where id=1 ;

1 rowupdated.

session2 session_id=18:

_dexter@FAKE>update tun2_tab set name ='dexter' where id=2 ;

1 rowupdated.

session3 session_id=9:

_dexter@FAKE>  update tun2_tab set name ='dexter' where id=1;

waiting...

来看一下锁的情况:

_sys@FAKE>/

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        9 TX      589850          0          6          0

        9 TM        82618          3          0         0       

        18 TX      196629          6          0          0       

        18 TM        82618          3          0          0       

        22 TX      589850          6          0          1        --session1正在阻塞 session 3

        22 TM        82618          3         0          0

6 rowsselected.

由上可以看到,对单个表可以加多个3级共享锁。

session2因为修改的是id=2 的记录,所以可以正常执行。

session3由于修改的是id=1 的记录,session1这个时候正在修改,并且对这一行的资源加了6级的排他锁。所以session3 发生了阻塞

需要等待session 1 释放后才可以顺利执行。

 

Session1

Session2

Session3

Description

T1

update tun2_tab set name = 'DEXTER' where id=1 ;

   

session1 update操作会对表加3级共享锁

T2

 

update tun2_tab set name ='dexter' where id=2 ;

 

session2 update操作 也会对表加3级共享锁,由于更新的记录不包括ssession1中更新的记录id=1。所以可以顺利执行

T3

   

update tun2_tab set name ='dexter' where id=1 ;

waiting…

session3 update操作 也会对表加3级共享锁,由于更新的记录包括ssession1中更新的记录id=1。所以无法顺利执行

Delete阻塞

其实对于delete、update、insert操作加锁操作大致相同,都会对表加3级共享锁,对修改的行加排他锁。

所以只要想要并发的修改表中相同的行,在第一个获取锁的事务没有结束前,后面的时候都会发生阻塞。

_dexter@FAKE>select * from tun2_tab ;

        ID NAME

--------------------------------------------------

        1 dexter

        2 dexter

        3 NN

session1 session_id=144 :

_dexter@FAKE>delete from tun2_tab where id =1 ;

1 rowdeleted.

session2 session_id=18 :

_dexter@FAKE>delete tun2_tab where id >1 ;

2 rowsdeleted.

session3 session_id=9 :

_dexter@FAKE>delete tun2_tab ;

waiting...

_sys@FAKE>/

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        9 TX      524317          0         6          0

        9 TM        82618          3          0          0

        18 TX      655383          6          0          0

        18 TM        82618          3          0          0

      144 TX      524317          6          0         1

      144 TM        82618          3          0          0

6 rowsselected.

发生了阻塞,只有当session 1 和session 2 的事务结束后,session 3 才可以顺利完成。

 

Session1

Session2

Session3

Description

T1

delete from tun2_tab where id =1 ;

     

T2

 

delete tun2_tab where id >1 ;

 

session2 delete 操作因为不包括session 1 中的id=1的记录,所以可以顺利执行

T3

   

delete tun2_tab ;

waiting …

session3 delete操做,因为需要获取id=1,id>1记录的事务锁,所以发生了等待。可以看到它首先是在等待id=1的事务锁。

下面有两个有趣的实验 有趣小实验1

_dexter@FAKE>select * from tun2_tab ;

        ID NAME

--------------------------------------------------

        1 dexter

        2 dexter

        3 NN

session1 session_id=22:

_dexter@FAKE>delete from tun2_tab where id =2 ;

1 rowdeleted.

session2 session_id=18:

_dexter@FAKE>update tun2_tab set name ='dexter' where id>1 ;

waiting...

session3 session_id=9:

_dexter@FAKE>delete tun2_tab where id = 3 ;

1 rowdeleted.

查看一下锁的情况:

_sys@FAKE>/

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        9 TX      393228          6          0          0

        9 TM        82618         3         0          0

        18 TX      131089          0          6          0

        18 TM        82618          3          0          0

        22 TX      131089          6          0          1

        22 TM        82618          3          0         0

6 rowsselected.

这里比较有趣了,因为session 2 update 的记录包括id=2这一行,所以在id=2这一行加锁的时候,这里发生了transaction enqueue,它还没来得及对任何记录加锁,就已经进入了等待中。

而session3执行的时候发现id=3 的这一行还没有锁标示,所以它顺利的对id=3 的记录加了锁。

这个时候我们rollback 第一条记录后

session1 :

_dexter@FAKE>rollback ;

Rollbackcomplete.

发现session2 依然处于等待状态中

再看一下锁的情况:

_sys@FAKE>/

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        9 TX      393228          6          0          1

        9 TM        82618          3          0          0

        18 TX      589840          6          0          0

        18 TX      393228          0          6          0

        18 TM        82618          3          0          0

这个时候我们可以看到session2又在等待session3的事务结束以便获取id=3这条记录的锁。

 

 

Session1

Session2

Session3

Description

T1

delete from tun2_tab where id =2 ;

     

T2

 

update tun2_tab set name ='dexter' where id>1 ;

waiting…

 

session 2 因为要获取id=2的记录的事务锁所以发生阻塞,等待session1 中的事务释放。

T3

   

delete tun2_tab where id = 3 ;

按照正常人的思维,比如说我。这一句应该等待session2中的事务才对。但是事实不是如此。因为session2陷入了阻塞,没还没有对id=3的记录加上事务锁,所以session3可以顺利执行。

T4

commit;

     

T5

 

still waiting

 

因为需要id=3的记录的事务锁,所以又被阻塞。

 

 

有趣小实验2

session1session_id=144:

_dexter@FAKE>delete from tun2_tab where id =3 ;

1 rowdeleted.

session2session_id=18:

_dexter@FAKE>  update tun2_tab set name ='dexter' whereid>1 ;

waiting..

session3session_id=9:

_dexter@FAKE>delete tun2_tab where id = 2 ;

waiting..

看一下锁情况:

_sys@FAKE>/

      SID TYPE        ID1     LMODE    REQUEST      BLOCK

-------------- ---------- ---------- ---------- ----------

        9 TX      196635          0          6          0

        9 TM        82618          3          0          0

        18 TX      196635          6          0          1

        18 TM        82618          3         0         0

        18 TX      458767          0          6          0

      144 TM        82618          3          0          0

      144 TX      458767          6          0          1

7 rowsselected.

session 3 也进入了等待中,因为session2 先获取了id=2 的行锁,然后等待id=3 的行锁。

 

Session1

Session2

Session3

Description

T1

delete from tun2_tab where id =3 ;

     

T2

 

update tun2_tab set name ='dexter' where id>1 ;

 

session 2 因为要获取id=3的记录的事务锁所以发生阻塞,但是在阻塞之前,以及对id=1|2的记录加了事务锁

T3

   

delete tun2_tab where id = 2 ;

waiting…

发生等待。

更多详情见请继续阅读下一页的精彩内容:


    
 
 

您可能感兴趣的文章:

  • Oracle 数据库(oracle Database)性能调优技术详解
  • oracle中lpad函数的用法详解
  • oracle修改scott密码与解锁的方法详解
  • 求.bash_profile配置oracle详解
  • Oracle数据库中分区功能详解
  • oracle指定排序的方法详解
  • 详解如何应用改变跟踪技术加速Oracle递增备份
  • oracle合并列的函数wm_concat的使用详解
  • oracle select执行顺序的详解
  • 使用Oracle数据挖掘API方法详解[图文]
  • Oracle多表级联更新详解
  • 安装Linux与Oracle数据库步骤详解
  • oracle求同比,环比函数(LAG与LEAD)的详解
  • 详解Linux平台下的Oracle数据库编程
  • oracle中去掉回车换行空格的方法详解
  • Oracle中job的使用详解
  • [Oracle] Data Guard 之 Redo传输详解
  • oracle用户权限管理使用详解
  • 深入ORACLE变量的定义与使用的详解
  • 详解Oracle的几种分页查询语句
  • oracle SQL递归的使用详解
  • 关于Oracle数据缓冲区的内部机制剖析
  • Oracle连接数过多释放机制
  • MSSQL与Oracle数据库事务隔离级别与锁机制对比
  • ORACLE锁机制深入理解
  • Oracle数据完整性和锁机制简析
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • [Oracle] 浅谈Lock与Latch
  • Linux Oracle 设置LOCK_SGA
  • Oracle 12c发布简单介绍及官方下载地址
  • 在linux下安装oracle,如何设置让oracle自动启动!也就是让oracle那个服务自动启动,不是手动的
  • oracle 11g最新版官方下载地址
  • 请问su oracle 和su - oracle有什么不同?
  • Oracle 数据库(oracle Database)Select 多表关联查询方式
  • 虚拟机装Oracle R12与Oracle10g
  • Oracle数据库(Oracle Database)体系结构及基本组成介绍
  • Oracle 数据库开发工具 Oracle SQL Developer
  • 如何设置让Oracle SQL Developer显示的时间包含时分秒
  • Oracle EBS R12 支持 Oracle Database 11g
  • Oracle 10g和Oracle 11g网格技术介绍
  • SCO unix下安装oracle,但没有光盘,请大家推荐一个oracle下载站点(unix版本的)。谢谢!!!!
  • oracle中如何把表中具有相同值列的多行数据合并成一行
  • 请问大家用oracle数据库, 用import oracle.*;下的东西么? 还是用标准库?
  • ORACLE日期相关操作
  • Linux /$ORACLE_HOME $ORACLE_HOME
  • ORACLE数据库常用字段数据类型介绍
  • Linux系统下Oracle的启动与Oracle监听的启动
  • Oracle 12c的九大最新技术特性介绍
  • 请问在solaris下安装ORACLE,用root用户和用oracle用户安装有什么区别么?
  • ORACLE中DBMS_RANDOM随机数生成包
  • 网间Oracle的连接,远程连接Oracle服务器??


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3