以前虽然在网上看到很多关于Oracle锁机制的描述,但总感觉哪里有缺陷不适合自己,因此花了点时间参考官网以及Tom Tyke的《Oracle 9i/10g/11g编程艺术》一书整理了一下Oracle锁相关的知识。

Ps:此博客经过多次编辑,以当前版为准。

官网网址参考:

11.2
10.2

一、Oracle数据库的锁类型:

根据保护的对象不同,Oracle数据库锁可以分为以下几大类:    
1、DML锁(data locks,数据锁),用于保护数据的完整性;    
2、DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;    
3、内部锁和闩(internal locks and latches),保护数据库的内部结构。 
 
二、接下来依次讨论以上三种锁结构:
1.DML锁
DML锁主要包括TM锁和TX锁,其中TM锁称为意向锁或表级锁,TX锁称为行级锁或事务锁。我们可以认为Oracle只有如下6种LMODE的锁,只是根据锁定的对象不同而有不同的名称,如6号的X锁,既可以是用于锁表的TM锁,也可以是TX锁,也可以是DDL锁。
1.1 TM锁(也叫意向锁/表级锁)
TM锁包含如下类型:

TM锁的兼容性如下:(Y表示兼容,N表示冲突)

1.2 TX锁

TX锁只包含一种类型的锁:
TX的本义是Transaction(事务),当一个事务第一次执行数据更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE语句进行查询时,它即获得一个TX(事务)锁,直至该事务结束(执行COMMIT或ROLLBACK操作)时,该锁才被释放。
在同一个事务中,无论是锁定一行,还是一百万行,对于Oracle来说锁开销是一样的。这点可能与其他数据库不一样(例如SQL Server),原因是针对Oracle的每行数据都有一个标志位来表示该行数据是否被锁定。这样就极大的减小了行级锁的维护开销,也不可能出现锁升级。数据行上的锁标志一旦被置位,就表明该行数据被加X锁。
注意TX锁在v$lock的lmode也是6,但是这个6与TM锁的6号X锁只是因为锁定的对象不同而被叫做了TX锁。

1.3 举例说明

当发出一个DML命令后会话获取一个3号的TM锁,和一个针对特定行的6号TX锁。
行级只有X锁,且锁模式为6,再次重申这里的6并不是指TM的6号表锁。
此外Oracle一个事务中无论锁定多少行只会获取一个TX锁(没有锁升级),但有多少个表对象就会获取多少个TM表级锁。
验证如下:

查询锁的语句为:

select sid,type,id1,lmode,request,block from v$lock l where sid in (select session_id from v$locked_object) and type in ('TM', 'TX') order by 1;

1.4 DML锁的总结:

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

写永远不会阻塞读。当一行被修改后,Oracle通过回滚段提供给数据的一致性读。
注意:
以上读写操作不会互相阻塞是指在DML锁级别不会,但在内存中依然会发生内部闩锁的争用造成读被阻塞。例如DDL锁可能会造成严重的library cache lock等待,导致select语句被阻塞。再比如热块争用也会造成写阻塞读,只不过表现是buffer busy waits而已。

2.DDL锁

重点:DDL是保护表结构定义的。

当DDL命令发出时,Oracle会自动在被处理的对象上添加DDL锁定,从而防止对象被其他用户所修改。当DDL命令结束以后,则释放DDL锁定。
DDL锁定不能显式的被请求,只有当对象结构被修改或者被引用时,才会在对象上添加DDL锁定。
并不是所有DDL都会触发DDL锁,例如现在的创建索引语句,就只会获取一个S模式的TM锁,因此不会阻塞读。而online模式创建索引的语句则只会获取一个2号的TM锁,因此连DML也不会被阻塞。
需要注意的是DDL总会提交,即便是执行不成功也是如此,因此如果在事务中执行了DDL语句会导致所有事物被提交。验证很容易,在一个窗口执行一条delete然后执行DDL,你会发现记录被不可逆转的删除了,RollBack无效。因此针对事务中的DDL请务必使用自治事务实现。
DDL锁有3种:
2.1 排他DDL锁  --即6号的TM锁(Exclusive DDL Locks)
一般对表的DDL语句都会获取一个X模式的TM锁,这是为什么在表结构更改时只能查询不能修改的原因。
 
2.2 共享DDL锁(Share DDL Locks)
共享DDL锁的常见情形为创建存储过程时,会尝试为所有涉及到的表添加共享DDL锁,这会允许类似的DDL操作并发,但会阻止所有想要获取排他DDL锁的会话(即更改表结构的会话)。
--我觉的可以认为这就是4号的TM表锁。
 
2.3 可中断解析锁(Breakable Parse Locks)
会话解析一条SQL或PLSQL代码块时,对于该语句引用的每一个对象都会施加解析锁,目的在于:如果以某种方式删除或修改了引用对象,可以将共享池中已经解析的缓存语句无效刷出。
之所以叫做可中断解析锁,是因为这种锁优先级很低可能会被其他互斥DDL操作打断。
每个SQL在解析时都会获取一个可中断解析锁,只要SQL语句还在shared pool中,这个锁就一直存在。
Library cache lock就属于可中断解析锁,可以认为Library cache lock是针对父游标句柄和子游标句柄的保护体,pin是针对父子游标的保护体。前者有三种模式:1 null,2 S,3 X 后者只有2 S,3 X两种模式。在进行解析时一般会获取共享模式的Library cache lock以防止内存对象被修改,之后转为NULL模式。
 
3.内部闩锁机制
Latches:

可译作闩或者栓,这是一种非常低级别的序列化结构,用于协调并发会话对于共享数据结构、文件等的访问。
闩可以防止并发会话破坏共享的内存资源,几个非常典型的场景是:
  • 多个会话同时修改数据
  • 读取的数据正在被其他会话修改
  • 重新分配内存
可能在这里会和事务锁混淆,但事务锁是锁定逻辑结构的,如表和行,但是闩却是锁定物理结构的,如内存中的数据块、执行计划链表等等。多个会话对于同一个对象的访问就需要闩来保护了,例如对于同一个数据块中不同行的访问就需要latch来保护,而闩的存在时间是极短的,因此可以实现高并发(其实Oracle高并发并非是真正的并发而是latch释放速度极快的串行访问)。
通常在SGA中一个latch可以保护多个对象,例如DBWn和LGWR进程从SGA中分配内存以便创建新的数据结构,为了防止冲突进程会使用一种叫做shared pool latch的闩来序列化分配操作,在内存分配完毕后其它进程可能会需要访问shared pool中的其他区域如library cache,此时闩只会锁住library cache而非整个shared pool。
通常情况下oracle进程获取闩的时间极短,一个简单的查询都会有成千上万次的闩的获取和释放,是完全不能由用户控制的。
闩的数目的增多,意味着并发量增大,可以通过v$latch视图来查看闩的使用情况,包括每种闩被请求和等待的次数。
Mutex:(Mutual exclusion object)
可以译作互斥体,这种结构很类似于闩,区别在于一种mutex只保护一种对象,而一种闩通常会保护多种对象。
mutex的优势在于:
  • mutex可以减少latch争用
  • mutex比latch占用更少的内存
  • share mode模式的mutex允许多个会话并发使用
其他内部锁:
这些是比mutex和latch更复杂的结构,oracle数据库使用以下几种内部锁:
1.Dictionary cache locks
2.File and log management locks
3.Tablespace and undo segment locks
这几种锁的解释有兴趣可以到官网看,平时基本观察不到,后两种基本都在多实例时出现。
 
拓展说明:

上边谈到了Library cache lock和Library cache pin,这里稍微解释下:
一、首先我们以Oracle 10.2之前版本作为基准来解释:主要来自于《Oracle8i Internal Services》一书的第四章
****************************************
Library cache的包含很多cache部分,它包含PLSQL代码块的、解析树、SQL执行计划等,它还包含一个由SQL引用的DIANA的数据库对象,此对象被用于进行PLSQL块的编译以及SQL解析和执行,尽管数据字典中也包含此类信息。此外library cache也包含例如同义词转换、依赖追踪等信息,当然还有library cache lock/pin等内存闩锁。
Library cache lock属于可中断解析锁,有NULL、S、X三种模式,而Library cache pin有S和X两种模式,在解析SQL时会话获取S模式的Library cache lock,解析完毕后转为NULL模式。如果有DDL操作更改了语句涉及的数据库对象,那么依赖于此数据库对象的所有library cache objects都会失效,失效过程就是失去NULL模式的library cache lock的过程。
****************************************
接下来先放一张图:
这是library cache中主链表的简易结构图,每个hash bucket对应一个父游标句柄的链表,LCO表示library cache objects,是父游标或者子游标。父子游标是一对一或者一对多的关系。
在了解了以上基本常识的情况下,再来看涉及的内存栓锁:
首次进行硬解析的会话需要获取library cache latch(只有独占模式,无队列)来生成父游标句柄,待添加X模式library cache lock后释放library cache latch进行父游标句柄构造,构造父游标句柄完毕后获取X(独占)模式的library cache pin来构造父游标,接下来获取X模式的library cache lock生成子游标句柄,最后获取X模式library cache pin构造子游标完成硬解析。
如果是在已经存在的父游标上进行硬解析那么就会添加S模式的父游标句柄library cache lock来获取X模式的父游标library cache pin,之后获取X模式的library cache lock/pin完成硬解析。
软解析时则先获取S模式的父游标句柄library cache lock,然后获取S模式父游标library cache pin、S模式子游标句柄library cache lock和S模式子游标library cache pin。
二、接下来讨论10.2之后的的变化:
library cache pin结构被Cursor:xxx类型的mutex取代,而在11.1之后library cache latch结构也被library cache:mutex xxx类型的mutex取代了。
那么全新的SQL硬解析时首先会在library cache:mutex X的保护下获取X模式的library cache lock,然后释放mutex并构造父游标句柄,之后获取Cursor:pin X构造父游标,然后获取子游标句柄library cache lock构造子游标句柄并释放父游标的Cursor:pin X,最后获取Cursor:pin X完成子游标的构造从而完成硬解析。
如果是已经存在的父游标进行硬解析,那么首先在library cache:mutex X的保护下获取S模式的library cache lock,之后获取Cursor:pin S来pin住父游标,然后获取X模式的library cache lock构造子游标句柄并释放父游标mutex,最后获取Cursor:pin X构造子游标完成硬解析。
如果是软解析那么首先在library cache:mutex X的保护下获取S模式的library cache lock,之后获取Cursor:pin S来pin住父游标,最后依次找到子游标句柄和子游标。
如果发生了Cursor:pin S wait on X,那么意味着有硬解析在发生,并且可能存在较高的version count,导致此父游标句柄下的所有游标无法拿到Cursor:pin S。还有一种情况是游标涉及的LCO发生了DDL导致所有句柄失效,此时需要进行重新编译获取X模式的子游标mutex,因此其他会话发生Cursor:pin S wait on X等待。
同样的library cache lock等待也意味着存在硬解析,只有硬解析才会获取X模式的library cache lock,由于library cache lock的获取需要mutex的保护,相应的mutex等待也会伴生,可能是library cache:mutex X或者Cursor:xxx类型的mutex,这取决于library cache lock的等待是在父游标句柄还是子游标句柄上,子游标句柄较为常见。
 
最后重要说明:
以上关于内存锁的解释绝大部分都是基于《Oracle内核技术揭秘》的关于shared pool的章节以及《Oracle Internals: An Introduction》一书,如有困惑可以翻书或在文章下方留言交流。
 
总结一下自己的观点:
DML和除可中断解析锁之外的DDL锁就是保护逻辑结构的结构体,而library cahce lock/pin、latch和mutex则是保护内存中物理结构的结构体,抛开DML锁,一般来说在内存中获取内存锁都需要latch和mutex的保护,常见的场景就是library cache中Library cache lock的获取需要library cache:mutex X的保护,以及Buffer pool中的buffer pin 需要cbc latch保护住hash bucket中涉及到本SQL的链表头。
从名字上就可以看出latch和mutex的保护对象,cursor: xxx这种mutex保护的是游标, cbc latch保护的则是cache buffer chain链表,library cahce:mutex(以前叫library cache latch)则是用于保护library cache的,具体说来也是hash bucket的父游标句柄链表,以此来获取parent cursor handler上的library cache lock。
 
Oracle官网已经没有太多更详细的关于内部闩锁的资料,更详细的关于内部latch和mutex的运作机制和种类,参考吕海波《Oracle内核技术揭秘》和Steve Adams的《Oracle 8i Internal Services》一书。

Oracle 锁机制探究的更多相关文章

  1. Oracle 锁机制

    本文参考自:ORACLE锁机制 1.oracle是一个多用户使用的共享资源,当多个用户并发的操作同一数据行时,那么在oracle数据库中就会存在多个事务操作统一数据行的操作,如果不对并发操作进行控制, ...

  2. oracle锁机制

    1 前言 数据库大并发操作要考虑死锁和锁的性能问题.看到网上大多语焉不详(尤其更新锁),所以这里做个简明解释,为下面描述方便,这里用T1代表一个数据 库执行请求,T2代表另一个请求,也可以理解为T1为 ...

  3. 【转载并整理】ORACLE锁机制

    转载文章:http://blog.csdn.net/liuyiy/article/details/25005393 转载文章:http://www.cnblogs.com/jiyuqi/p/37017 ...

  4. oracle 锁的介绍 (转)

    本文转自:http://blog.csdn.net/gyb2013/article/details/6929697 一.什么是锁: Oracle的锁机制是一种轻量级的锁定机制,不是通过构建锁列表来进行 ...

  5. oracle 事务 锁机制

    原文地址:http://www.cnblogs.com/quanweiru/archive/2013/05/24/3097367.html 本课内容属于Oracle高级课程范畴,内容略微偏向理论性,但 ...

  6. ORACLE的锁机制

    数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性. 加锁是实现数据 ...

  7. (转)MySQL优化笔记(八)--锁机制超详细解析(锁分类、事务并发、引擎并发控制)

    当一个系统访问量上来的时候,不只是数据库性能瓶颈问题了,数据库数据安全也会浮现,这时候合理使用数据库锁机制就显得异常重要了. 原文:http://www.jianshu.com/p/163c96983 ...

  8. Hibernate中的锁机制

    锁机制:是数据库为了保证数据的一致性<一个事务的各种操作不相互影响>而使各种共享资源在被并发访问访问变得有序所设计的一种规则,用来保证在当前用户进行操作数据的时候其他的用户不能对同一数据进 ...

  9. MySQL学习笔记十六:锁机制

    1.数据库锁就是为了保证数据库数据的一致性在一个共享资源被并发访问时使得数据访问顺序化的机制.MySQL数据库的锁机制比较独特,支持不同的存储引擎使用不同的锁机制. 2.MySQL使用了三种类型的锁机 ...

随机推荐

  1. PYTHON 格式字符串中的填充符

    使用 %类型 来填充 常用的有:%s 填充字符串类型:%d 填充 int 类型:这里是沿用了 C语言中 printf() 函数中的格式,更多的信息请查看:完整列表 name = 'tommy' mes ...

  2. SpringCloud实战10-Sleuth

    Spring-Cloud-Sleuth是Spring Cloud的组成部分之一,为SpringCloud应用实现了一种分布式追踪解决方案,其兼容了Zipkin, HTrace和log-based追踪, ...

  3. 3.Magicodes.NET框架之路——预览(一)

    3.Magicodes.NET框架之路——预览(一) 前言 一眨眼,已经过去两个多月了 ,哥已经火力全开了(业余时间和精力,甚至为此放弃了各种私活),所以大家不要抱怨慢哈.编程犹如逆水行舟,不进则退. ...

  4. 翻译:DECLARE HANDLER语句(已提交到MariaDB官方手册)

    本文为mariadb官方手册:DECLARE HANDLER的译文. 原文:https://mariadb.com/kb/en/library/declare-handler/我提交到MariaDB官 ...

  5. With As 用法

    含义:WITH AS 短语,也叫做子查询部分(subquery factoring)也称公用表表达式(CTE), ,可以定义一个SQL片断,该SQL片断会被整个SQL语句用到.可以使SQL语句的可读性 ...

  6. mybatis_04 resultType和resultMap区别

    resultType 使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功. 如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象: 如 ...

  7. 《Unix网络编程》读书笔记

    UDP和TCP UDP(User Datagram Protocol,用户数据报协议)是一个无连接协议,不保证UDP数据报会到达其最终目的地,不保证各数据报的先后顺序跨网络后保持不变,也不保证每个数据 ...

  8. What does operator “dot” (.) mean?

    Question: Given the code : A = [1 2 3; 3 2 1] B = A.^2 The output : B = 1 4 9 9 4 1 But if I do this ...

  9. SQL优化一(SQL使用技巧)

    1.行列转换: decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值); select decode(sign(变量1-变量2),-1,变量1,变量2) from dual ...

  10. JavaScript 笔记(一)

    Number 1.2345e3=1.2345*1000 NaN//not a num 无法计算结果 Infinity //无限大 数组 var arr=[1,2,'hello'] 下标从0开始 对象 ...