Oracle锁机制及锁的探讨
一、 Oracle锁机制
1、什么是锁
锁是控制“共享资源”并发存取的一种机制。注意这里说“共享资源”而不仅指“数据行”,数据库的却在行一级对表的数据加锁,但是数据库也在其它地方对各种资源的并发存取使用锁。比如说,如果一个存储过程在执行过程中,它会被加上某种模式的锁只允许某些用户执行它而不允许其他用户修改它。锁在数据库中被用来实现允许对共享资源的并发存取,同时保证数据的完整性和一致性。
2、锁的类型
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于实现并发存取并保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构,比如数据库解析了一条查询语句并生成了最优化的执行计划,它将把这个执行计划“latche”在library cache中然后供其它session使用。
DML锁的目的在于保证并发情况下的数据完整性,它也是我们最常见和常用的锁,本文我们主要讨论DML锁。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁(用来保证表的结构不被用户修改),TX锁称为事务锁或行级锁。当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。如表1所示。
表1:Oracle的TM锁模式 | |||
锁模式 | 锁描述 | 解释 | SQL操作 |
0 | none |
|
|
1 | NULL | 空 | Select |
2 | SS(Row-S) | 行级共享锁,其他对象只能查询这些数据行 | Select for update、Lock for update、Lock row share |
3 | SX(Row-X) | 行级排它锁,在提交前不允许做DML操作 | Insert、Update、Delete and so on |
4 | S(Share) | 共享锁 | Create index、Lock share |
5 | SSX(S/Row-X) | 共享行级排它锁 | Lock share row exclusive |
6 | X(Exclusive) | 排它锁 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
在数据行上只有X锁(排他锁)。在 Oracle数据库中,当一个事务首次发起一个DML语句时就获得一个TX锁,该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行DML语句时,第一个会话在该条记录上加锁,其他的会话处于等待状态。当第一个会话提交后,TX锁被释放,其他会话才可以加锁。
当Oracle数据库发生TX锁等待时,如果不及时处理常常会引起Oracle数据库挂起,或导致死锁的发生,产生ORA-60的错误。这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。
3、监控锁的相关视图
表2:数据字典视图说明 | ||
视图名 | 描述 | 主要字段说明 |
v$session | 查询会话的信息和锁的信息。 | sid,serial#:表示会话信息。 program:表示会话的应用程序信息。 row_wait_obj#:表示等待的对象。 和dba_objects中的object_id相对应。 |
v$session_wait | 查询等待的会话信息。 | sid:表示持有锁的会话信息。 Seconds_in_wait:表示等待持续的时间信息。 Event:表示会话等待的事件。 |
v$lock | 列出系统中的所有的锁。 | Sid:表示持有锁的会话信息。 Type:表示锁的类型。值包括TM和TX等。 ID1:表示锁的对象标识。 lmode,request:表示会话等待的锁模式的信息。用数字0-6表示,和表1相对应。 |
dba_locks | 对v$lock的格式化视图。 | Session_id:和v$lock中的Sid对应。 Lock_type:和v$lock中的type对应。 Lock_ID1: 和v$lock中的ID1对应。 Mode_held,mode_requested:和v$lock中的lmode,request相对应。 |
v$locked_object | 只包含DML的锁信息,包括回滚段和会话信息。 | Xidusn,xidslot,xidsqn:表示回滚段信息。和v$transaction相关联。 Object_id:表示被锁对象标识。 Session_id:表示持有锁的会话信息。 Locked_mode:表示会话等待的锁模式的信息,和v$lock中的lmode一致。 |
二、 锁的探讨
在我们讨论之前先来看一个关于锁的问题,这些问题大多都是因为那些设计不好的应用程序错误的使用(或没有使用)数据库锁机制引起的。
1、更新丢失
“更新丢失”是一个典型的数据库问题,在所有的多用户环境都可能遇到。简单的描述下“更新丢失”的产生:
1)session1的一个事务查询一行数据展现给user1。
2)另一个session2的一个事务也查询同一行数据展现给user2。
3)然后user1通过应用程序更新并提交这行数据,他完成了整个事务。
4)User2也同样通过应用程序更新并提交这行数据,他也完成了整个事务。
上面的过程就会造成“更新丢失”,因为所有在第三步修改的数据全部都会丢失。一个典型的例子就是售票系统,比如一个用户(user1)在网上预定查询到1号位的票还没售出,同时另一用户(user2)在现场售票点查询也查到1号位票没售出。然后user1预订了这张票(即售票系统更新了数据库表中1号位的信息“已预订”),而这时user2又将这张票卖给了现场购票的人(即user2也成功更新1号位的信息“已售”,覆盖更新了user1的更新),等到user1去拿票的时候他预定的票却已经被卖出去了,这就是应用系统出现的一个严重的问题。
2、悲观锁
“悲观锁”实际上是一种使用锁的方式,即user1主观的认为会发生“更新丢失”,所以在他查询的时候就对查询结果的数据“立刻”加锁来防止发生“更新丢失”。这是一种“悲观”的想法,所以叫做“悲观锁”。
“悲观锁”一般用于独占连接的数据库环境,至少是一个用户在一个事务的生存周期中独占这个连接,比如C/S这种结构的系统中。下面模拟下应用中如何使用“悲观锁”:
Session1:
//session1应用程序先查询信息(不加锁)
SQL> select * from test1;
ID NAME SEX
---------- ------------------------------ --------------------
100 iceberg3521 male
101 singlelove male
102 myself male
103 fengzhu male
104 test female
//session1的用户想修改id=102的这条记录,取出这条记录的值绑定到变量
SQL> variable id number
SQL> variable name varchar2(30)
SQL> variable sex varchar2(20)
SQL> exec :id :=102; :name :='myself'; :sex :='male';
PL/SQL 过程已成功完成。
//再简单查询看要修改的行是否已被其它session修改,并对要修改的行加锁,这里使用select for update nowait来对需要修改的行进行加锁。
SQL> select * from test1 where id=:id
2 and name=:name
3 and sex=:sex
4 for update nowait;
ID NAME SEX
---------- ------------------------------ --------------------
102 myself male
这里session1重复查询并对准备修改的行加锁来防止其它session来修改这行,这种方法就叫做“悲观锁”,因为我们悲观的人为从我们查询到修改这段时间会有其他人来修改我们打算修改的记录。
这一步实际会有三种结果:
1)102这条记录没有被其他人修改,我们就重新查询出来这条记录并成功对其加锁。
2)102这条记录正在被人修改,我们加得到下面这个结果:
SQL> select * from test1 where id=:id
2 and name=:name
3 and sex=:sex
4 for update nowait;
select * from test1 where id=:id
*
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源
3)如果102这条记录已经被人修改,我们的查询将返回
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7668955/viewspace-1002160/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/7668955/viewspace-1002160/