一、概述
锁是协调对共享资源访问的一种机制。此处共享资源可能是数据行、表或者别的什么很多人都需要访问的资源。
Oracle数据库实现锁的机制跟别的数据库不同,在Oracle数据库中锁并不算的上是稀缺的资源,当然不合适的持有很多锁一定会降低程序的并发行和扩展性的。
二、锁定问题
考虑下这样一种场景,表T中有一行数据记录了一个人的信息,A和B两个客户端都要去修改,A和B都先获取了这个人的信息,然后A会修改地址,B会修改了证件号码。修改完后A先提交了修改,把用户的信息更新了一遍,提交事务后,B也进行了修改,提交。此时再去查看此人信息,发现A做的修改已经被覆盖,即相当于A没有进行任务操作。
解决问题的办法有两种:悲观锁定和乐观锁定
悲观锁定:当一个客户端要修改一条记录的时候, 就把该记录锁定,直到修改完提交了事务,如通过select * from T for update。这种办法当然有很一些问题了,在并发情况下对记录的锁定时间很长,如果是一些比较核心的资源,这种方式会极大降低并发度。在另外一些更新数量的场景下,情况变得更糟糕。
另外,如果是b/s应用模式,这问题就变得复杂了,每次请求一个事务,打开用户信息的时候,事务就已经完了,这种行上的锁也被释放了,等真正更新的时候已经没有了锁。
乐观锁定:我们在修改记录的时候,不像悲观锁定一样,一开始便锁定。而是在开始的时候记录一个关键的信息,等 真正要修改时候根据这个信息来判断我们在开始决定修改的时候到更新时候为止,有没有被别人更新过,如果更新过了,那么我们就提示修改失败,需要重新来修改。此处的关键信息可以是版本列,如时间戳;也可以是校验和,如该行一些关键字段或者所有字段值的hash/md5值,也可以作为一个虚拟列‘存放’hash/md5值。
但是另外考虑一种情况,在修改包含大量信息的表单的时候,用户辛辛苦苦录了半个小时的单据,在提交的时候说表单已经被修改了,你猜猜那会是什么样的情形?所以作为对悲观锁的一种扩展,我们可以在应用层级实现一种锁定,应用层负责添加、释放锁,并负责客户端处理异常终止、会话超时等情形下锁的释放,同时提供应用级锁定的管理功能,可以管理员手动释放锁。
三、锁
1)、DML锁
顾名思义就是执行dml语句时候加的锁,如update、delete、select、insert等。怎么分成tm和tx锁的?在oracle数据库中select语句是从来不加锁的,对于一个大表,你在一个会话中查询还没有完成的时候,可以在另外一个会话中把表给drop掉,第一个会话中的查询会一直进行到查完所有数据。
a、TX锁
事务锁,属于行级锁,如果当前没有事务,则第一条修改表数据的sql语句将隐式的开启一个新事务,容易update、 delete、 insert语句,同时该事务会持有一个tx锁,这些语句修改的数据也将指向这把tx锁。如果已经有了事务,则直接指向已有的tx锁。
分别用sys和scott连接数据库,然后用sys查看scott持有的锁:
SQL> select sess.username,sess.sid,lck.type,lck.lmode
from v$session sess
left join v$lock lck on lck.sid = sess.sid
where sess.username = upper('scott');
USERNAME SID TYPE LMODE
--------------------- ---------- ---- ----------
SCOTT 132 AE 4
然后用scott更新emp的一条记录后再查询锁的信息:
SQL> select sess.username,sess.sid,lck.type,lck.lmode
2 from v$session sess
3 left join v$lock lck on lck.sid = sess.sid
4 where sess.username = upper('scott');
USERNAME SID TYPE LMODE
---------------------------- ---------- ---- ----------
SCOTT 132 AE 4
SCOTT 132 TM 3
SCOTT 132 TX 6
此处多出了一把TX锁。如果继续用scott更新别的表,如dept表,会看到tm锁增加了一把,但是tx锁仍然仍然是一把。
b、TM锁
表级锁,Enqueue锁,保护表结构不被别的会话修改。当对表数据进行增删改的时候,就会给表加一个TM锁。上边代码中看到,在修改表数据的时候会给表加一把tm锁。
如果一个表加了tm锁,则不能再加ddl排他锁和ddl共享锁了。
如果向表中插入数据后,事务尚未提交,在新会话中再创建索引则会失败,提示(什么锁跟什么锁的问题?):
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效。
但是如果在在运行创建索引语句但是并未创建完成的时候,另外一个会话中插入数据,会出现数据插入,索引创建会话等待插入数据会话提交事务的现象,为何?
2)、DDL锁
顾名思义是执行ddl语句时候加的锁,如create table、alter table、drop table、truncate table、create index、create view等。
a、DDL互斥锁(DDL exclusive lock)
表级锁,当对一个表加了ddl互斥锁的时候,别的会话就不能再加ddl锁和dml锁了,修改表结构会被阻塞,查表中的数据也会被阻塞。如alter table,create table,drop table,truncate table等。
b、DDl共享锁(DDL share lock)
表级锁,当一个表加了ddl共享锁的时候,别的会话只能获得ddl共享锁,不能加dml锁,不能修改表结构,但是可以查询修改表中的数据。如create view,create index等。
c、可中断解析所(breakable parse lock)
共享池(只有共享池中么?)中一些对象,如执行计划,游标,统计信息等,会对依赖的一些对象,如表,索引等加可中断解析锁。如果被依赖对象发生了变化,如执行了ddl,oracle会查看已经对该对象注册了依赖性的对象列表,使其失效。
ddl锁可以通过dba_ddl_locks视图获取,这是一个建立在x$表上的视图。
一个会话中执行如下sql但并未执行完时:
create index idx_dpt_bk_deptno on scott.dept_bak(deptno);
另外一会话中执行查询,最后一行就是创建索引的ddl锁。
SQL> select * from dba_ddl_locks;
SESSION_ID OWNER NAME TYPE MODE_HELD MODE_REQUESTED
---------- ----- ------------------ ------------ ------------- -------------
190 SYS "SYS"."ALERT_QUE":"HAE_SUB" 28 Null None
190 SYS "SYS"."ALERT_QUE":"HAE_SUB" 28 Null None
190 SYS STANDARD Table/Procedure/Type Null None
190 SYS DBMS_PRVT_TRACE Table/Procedure/Type Null None
191 SYS IS_VPD_ENABLED Table/Procedure/Type Null None
190 SYS "SYS"."ALERT_QUE":"YYMT_1830_O 28 Null None
190 SYS AQ$_ALERT_QT_E 10 Null None
191 SYS DBMS_APPLICATION_INFO Body Null None
190 SYS DBMS_HA_ALERTS_PRVT Table/Procedure/Type Null None
191 SYS SQL_TXT Table/Procedure/Type Null None
191 SCOTT IDX_DPT_BK_DEPTNO Index Exclusive None
四、闩
闩是一种低级串行化设备,用来协调对内存结构如数据库块缓冲区缓存和共享池中的库缓存、对象、文件等资源的并发访问。
闩设计为只持有很短的一小段时间,获取闩的时候,如果获取不到则休眠一小段时间后继续获取,不会排队等待。而enqueue锁是队列锁,如果获取队列锁获取不到则会排队。
在获取不到闩的时候,就会出现“自旋”,即在循环中不断重复的去获取闩。因为进程上下文切换的的代价很高,而闩本身被设计为持有很小一段时间的设备,所以进程在被踢出cpu之前会不断重复的试图获取栓,如果循环了一定次数后仍然获取不到,就会被踢出cpu。这个循环的次数可以通过参数设置,默认为2000.可以通过statspack或v$latch视图来查看视图获取栓的信息。
可以通过硬解析和软解析的例子来进一步了解一些闩的细节。
五、手动锁定和用户定义锁
1)手动锁定:通过select ···· for update 或lock table手工锁定
2)用户自定义锁:通过dbms_lock包可以创建用户过户自定义锁。
相关推荐
以上每个章节都包含了一系列实用的脚本和指导,可以帮助数据库管理员深入理解Oracle性能优化的关键要素,并提供实际操作的工具。通过学习和应用这些脚本,可以在面临性能挑战时找到解决方案,提升Oracle数据库的整体...
- **锁类型**:详述了数据操纵语言(DML)锁、数据定义语言(DDL)锁、闩锁和内部锁(enqueue)等不同类型锁的特点和用途。 - **手动锁定和用户自定义锁**:介绍了在特定情况下如何实现手动锁定和创建用户自定义锁。 - *...
### Oracle8i内部服务:等待、闩锁、锁定与内存管理关键知识点解析 #### 标题及描述概览 本书《Oracle8i Internal Services for Waits, Latches, Locks, and Memory》由Steve Adams撰写,是针对Oracle数据库内部...
- **数据库**:Oracle数据库由一系列物理文件组成,用于存储数据和元数据。 - **实例**:每个数据库都有一个或多个实例与之关联,实例是指运行数据库的软件部分,包括内存结构和后台进程。 ##### 2.2 SGA和后台进程...
#### 十七、等待事件、锁和闩锁 - **等待事件分析**:解释了Oracle RAC中常见的等待事件类型及其对性能的影响。 - **锁管理**:讨论了如何有效管理锁以减少并发冲突。 - **闩锁优化**:介绍了闩锁的工作机制以及...
- 支持并发访问:通过锁和闩锁机制允许多个进程安全地访问同一数据块。 #### 二、Buffer Cache 内存结构 **2.1 Buffer Cache 结构概述** Buffer Cache 的内存结构主要包括 Hash Bucket 和 Buffer Header。 - **...
Oracle通过多种类型的锁来管理并发,包括TX锁、TM锁、DDL锁以及闩(lock)和队列锁(enqueue),每种锁针对不同场景下资源的访问和保护。例如,TX锁用于保证数据修改过程中的独占访问,而TM锁和DDL锁则分别用于保护对象...
4. **其他结构**,如锁和闩锁,用于数据一致性控制,以及数据状态信息。 后台进程在Oracle实例中起着关键作用,例如DBWR(数据库写入器)负责将数据缓冲区中的更改写入数据文件,LGWR(日志写入器)将重做日志缓冲...
- 内部锁(闩锁和队列):用于保护内存结构免受并发访问的影响。 - 手动锁:由应用程序显式设置的锁。 - **并发控制**:介绍了事务隔离级别的概念,以及不同的隔离级别如何影响并发处理。 - **事务隔离级别**: -...
Oracle 9i 提供了一系列工具帮助管理员监控和诊断数据库性能问题,包括但不限于: - **AWR (Automatic Workload Repository)**:自动收集关于系统活动的信息,用于分析性能瓶颈。 - **ADDM (Automatic Database ...