ORACLE锁机制
http://www.cnblogs.com/gengyulong/archive/2011/04/07/2007586.html数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同
时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致
性。
加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发
出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不
能对此数据对象进行更新操作。
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁
)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他
事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
Oracle数据库的锁类型
根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护
数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结
构定义;内部锁和闩(internal locks and latches),保护 数据库的内部结构。
DML锁的目的在于保证并发情况下的数据完整性,。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其
中TM锁称为表级锁,TX锁称为事务锁或行级锁。
当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请
TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用
再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S
、X 等多种模式,在数据库中用0-6来表示。不同的sql操作产生不同类型的TM锁。
在数据行上只有X锁(排他锁)。在Oracle数据库中,当一个事务首次发起一个DML语句时就获得一个TX
锁,该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行 DML语句时,第一个会
话在该条记录上加锁,其他的会话处于等待状态。当第一个会话提交后,TX锁被释放,其他会话才可以
加锁。
当Oracle数据库发生TX锁等待时,如果不及时处理常常会引起Oracle数据库挂起,或导致死锁的发生,
产生ORA-60的错误。这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。
悲观封锁和乐观封锁
一、悲观封锁
锁在用户修改之前就发挥作用:
Select ..for update(nowait)
Select * from tab1 for update
用户发出这条命令之后,oracle将会对返回集中的数据建立行级封锁,以防止其他用户的修改。
如果此时其他用户对上面返回结果集的数据进行dml或ddl操作都会返回一个错误信息或发生阻塞。
1:对返回结果集进行update或delete操作会发生阻塞。
2:对该表进行ddl操作将会报:Ora-00054:resource busy and acquire with nowait specified.
原因分析
此时Oracle已经对返回的结果集上加了排它的行级锁,所有其他对这些数据进行的修改或删除操作都必
须等待这个锁的释放,产生的外在现象就是其他的操作将发生阻塞,这个这个操作commit或rollback.
同样这个查询的事务将会对该表加表级锁,不允许对该表的任何ddl操作,否则将会报出ora-00054错误
::resource busy and acquire with nowait specified.
二、乐观封锁
乐观的认为数据在select出来到update进取并提交的这段时间数据不会被更改。这里面有一种潜在的危
险就是由于被选出的结果集并没有被锁定,是存在一种可能被其他用户更改的可能。因此Oracle仍然建
议是用悲观封锁,因为这样会更安全。
阻塞
定义:
当一个会话保持另一个会话正在请求的资源上的锁定时,就会发生阻塞。被阻塞的会话将一直挂起,直
到持有锁的会话放弃锁定的资源为止。4个常见的dml语句会产生阻塞
INSERT
UPDATE
DELETE
SELECT…FOR UPDATE
INSERT
Insert发生阻塞的唯一情况就是用户拥有一个建有主键约束的表。当2个的会话同时试图向表中插入相同
的数据时,其中的一个会话将被阻塞,直到另外一个会话提交或会滚。一个会话提交时,另一个会话将
收到主键重复的错误。回滚时,被阻塞的会话将继续执行。
UPDATE 和DELETE当执行Update和delete操作的数据行已经被另外的会话锁定时,将会发生阻塞,直到另
一个会话提交或会滚。
Select …for update
当一个用户发出select..for update的错作准备对返回的结果集进行修改时,如果结果集已经被另一个
会话锁定,就是发生阻塞。需要等另一个会话结束之后才可继续执行。可以通过发出 select… for
update nowait的语句来避免发生阻塞,如果资源已经被另一个会话锁定,则会返回以下错误:Ora-
00054:resource busy and acquire with nowait specified.
死锁-deadlock
定义:当两个用户希望持有对方的资源时就会发生死锁.
即两个用户互相等待对方释放资源时,oracle认定为产生了死锁,在这种情况下,将以牺牲一个用户作为代
价,另一个用户继续执行,牺牲的用户的事务将回滚.
例子:
1:用户1对A表进行Update,没有提交。
2:用户2对B表进行Update,没有提交。
此时双反不存在资源共享的问题。
3:如果用户2此时对A表作update,则会发生阻塞,需要等到用户一的事物结束。
4:如果此时用户1又对B表作update,则产生死锁。此时Oracle会选择其中一个用户进行会滚,使另一个
用户继续执行操作。
起因:
Oracle的死锁问题实际上很少见,如果发生,基本上都是不正确的程序设计造成的,经过调整后,基本
上都会避免死锁的发生。
DML锁分类表
表1Oracle的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、Lock row share
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
oracle 锁问题的解决
可以用Spotlight软件对数据库的运行状态进行监控。
当出现session锁时,我们要及时进行处理.
1. 查看哪些session锁:
sql语句:select 'alter system kill session '''||sid||','||serial#||''';' from v$session
where sid in (select sid from v$lock where block = 1);
sql> select 'alter system kill session '''||sid||','||serial#||''';' from v$session where
sid in (select sid from v$lock where block = 1);
'ALTERSYSTEMKILLSESSION'''||SID||','||SERIAL#||''';'
--------------------------------------------------------------------------------
alter system kill session '132,731';
alter system kill session '275,15205';
alter system kill session '308,206';
alter system kill session '407,3510';
2. 查看session锁.
sql语句:select s.sid,q.sql_text from v$sqltext q,v$session s
where q.address = s.sql_address
and s.sid = &sid
order by piece;
sql> select s.sid,v$session s where q.address = s.sql_address
and s.sid in (select sid from v$lock where block = 1) order by piece;
SID sql_TEXT
---------- ----------------------------------------------------------------
77 UPDATE PROFILE_USER SET ID=1,COMPANY_ID=2,CUSTOMER_ID=3,NAMED
77 _INSURED_ID=4,LOGIN=5,ROLE_ID=6,PASSWORD=7,EMAIL=8,TIME_ZON
77 E=9 WHERE PROFILE_USER.ID=:34
3 rows selected.
3. kill锁的进程.
sql语句:alter system kill session '77,22198';
sql> alter system kill session '391,48398';
System altered.
4. 查看谁锁了谁。
select s1.username || [email='@']'@'[/email] || s1.machine
|| ' ( SID=' || s1.sid || ' ) is blocking '
|| s2.username || [email='@']'@'[/email] || s2.machine || ' ( SID=' || s2.sid || ' ) ' AS
blocking_status
from v$lock l1,v$session s1,v$lock l2,v$session s2
where s1.sid=l1.sid and s2.sid=l2.sid
and l1.BLOCK=1 and l2.request > 0
and l1.id1 = l2.id1
and l2.id2 = l2.id2 ;
注:
> : 重定向输出,将文件的标准输出重新定向输出到文件,或将数据文件作为另一程序的标准输入内容
。
| :UNIX管道:将一文件的输出作为另一文件的输入.
在执行sql语句试:alter system kill session '391,48398'(sid为391); 应当注意对于sid在100以下
的应当谨慎,可能该进程对应某个application,如对应某个事务,可以kill.
本文来自CSDN博客,转载请标明出处:
http://blog.csdn.net/tianlesoftware/archive/2009/10/20/4696896.aspx
========
ORACLE里几种锁模式
http://blog.csdn.net/lxlj2006/article/details/5999458Oracle里锁有以下几种模式:
0:none
1:null 空
2:Row-S 行共享(RS):共享表锁
3:Row-X 行专用(RX):用于行的修改
4:Share 共享锁(S):阻止其他DML操作
5:S/Row-X 共享行专用(SRX):阻止其他事务操作
6:exclusive 专用(X):独立访问使用
数字越大锁级别越高,影响的操作越多。
一般的查询语句如select ... from ... ;是小于2的锁,有时会在v$locked_object出现。
select ... from ... for update; 是2的锁。
当对话使用for update子串打开一个游标时,
所有返回集中的数据行都将处于行级(Row-X)独占式锁定,
其他对象只能查询这些数据行,不能进行update、delete或select...for update操作。
insert / update / delete ... ; 是3的锁。
没有commit之前插入同样的一条记录会没有反应,
因为后一个3的锁会一直等待上一个3的锁,我们必须释放掉上一个才能继续工作。
创建索引的时候也会产生3,4级别的锁。
locked_mode为2,3,4不影响DML(insert,delete,update,select)操作,
但DDL(alter,drop等)操作会提示ora-00054错误。
有主外键约束时 update / delete ... ; 可能会产生4,5的锁。
DDL语句时是6的锁。
以DBA角色,查看当前数据库里锁的情况可以用如下sql语句:
select object_id,session_id,locked_mode from v$locked_object;
select t2.username,t2.sid,t2.serial#,t2.logon_time
from v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by t2.logon_time;
如果有长期出现的一列,可能是没有释放的锁。
我们可以用下面sql语句杀掉长期没有释放非正常的锁:
alter system kill session 'sid,serial#';
如果出现了锁的问题,某个DML操作可能等待很久没有反应。
当你采用的是直接连接数据库的方式,
也不要用OS系统命令 $kill process_num 或者 $kill -9 process_num来终止用户连接,
因为一个用户进程可能产生一个以上的锁,杀OS进程并不能彻底清除锁的问题。
记得在数据库级别用alter system kill session 'sid,serial#';杀掉不正常的锁。
当事务获得行锁后,此事务也将自动获得该行的表锁(共享锁),以防止其它事务进行DDL语句影响
记录行的更新。事务也可以在进行过程中获得共享锁或排它锁,只有当事务显示使用LOCK TABLE语句显
示的定义一个排它锁时,事务才会获得表上的排它锁,也可使用LOCK TABLE显示的定义一个表级的共享锁
,所以行锁的时候我还的拿个表锁,免得其他人该了我的表结构或者删除了我的表。
表级锁兼容性:
========
oracle查看锁表进程,杀掉锁表进程
http://www.iteye.com/topic/571315查看锁表进程sql语句1:
select sess.sid,
sess.serial#,
lo.oracle_username,
lo.os_user_name,
ao.object_name,
lo.locked_mode
from v$locked_object lo,
dba_objects ao,
v$session sess
where ao.object_id = lo.object_id and lo.session_id = sess.sid;
查看锁表进程sql语句2:
select * from v$session t1,v$locked_object t2 where t1.sid = t2.SESSION_ID;
杀掉锁表进程:
如有記錄則表示有lock,記錄下SID和serial# ,將記錄的ID替換下面的738,1429,即可解除LOCK
alter system kill session '738,1429';
Oracle有自己的进程管理策略,很多情况下杀进程往往不能即使生效,可以加alter system kill ...
immediately 试试
还是应该找到锁表的原因,从根源上解决避免这个问题产生。
========
ORACLE六大锁模式级别越高影响越多
http://www.2cto.com/database/201307/227562.html
ORACLE里锁有以下几种模式:
0:none
1:null 空
2:Row-S 行共享(RS):共享表锁,sub share
3:Row-X 行独占(RX):用于行的修改,sub exclusive
4:Share 共享锁(S):阻止其他DML操作,share
5:S/Row-X 共享行独占(SRX):阻止其他事务操作,share/sub exclusive
6:exclusive 独占(X):独立访问使用,exclusive
数字越大锁级别越高,影响的操作越多。
1级锁有:Select,有时会在v$locked_object出现。
2级锁有:Select for update,Lock For Update,Lock Row Share
select for update当对话使用for update子串打开一个游标时,所有返回集中的数据行都将处于行级
(Row-X)独占式锁定,其他对象只能查询这些数据行,不能进行update、delete或select for update操
作。
3级锁有:Insert,Update,Delete,Lock Row Exclusive
没有commit之前插入同样的一条记录会没有反应,因为后一个3的锁会一直等待上一个3的锁,我们必须
释放掉上一个才能继续工作。
4级锁有:Create Index,Lock Share
locked_mode为2,但DDL(alter,drop等)操作会提示
ora-00054错误。
00054,00000,"resource busy and acquire with NOWAIT specified"
// *Cause: Resource interested is busy.
// *Action: Retry if necessary.
5级锁有:Lock Share Row Exclusive
具体来讲有主外键约束时update / delete ... ; 可能会产生4,5的锁。
6级锁有:
?
Alter table,Drop table,Drop Index,Truncate table,Lock Exclusive
以DBA角色,查看当前数据库里锁的情况可以用如下sql语句:
<CCID_NOBR>
<CCID_CODE>col owner for a12
col object_name for a16
select b.owner,b.object_name,l.session_id,l.locked_mode
from v$locked_object l,dba_objects b
where b.object_id=l.object_id
/
select t2.username,t2.logon_time
from v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by t2.logon_time
/
如果有长期出现的一列,可能是没有释放的锁。我们可以用下面sql语句杀掉长期没有释放非正常的锁:
?
1
2
<CCID_NOBR>
<CCID_CODE>alter system kill session 'sid,serial#';
如果出现了锁的问题,某个DML操作可能等待很久没有反应。
当你采用的是直接连接数据库的方式,也不要用OS系统命令 $kill process_num 或者 $kill -9
process_num来终止用户连接,因为一个用户进程可能产生一个以上的锁,杀OS进程并不能彻底清除锁的
问题。
========
Oracle锁机制原理(深入剖析)
http://www.2cto.com/database/201309/240500.html库用两种类型的锁,一种是共享锁,另一种是排他锁。在像表或是表中一行只能获得一个排他锁,但是
共享锁可以再单个的资源中被多次获得。
锁影响读和写相互作用。下面的一些规则综述了oracle数据库关于读和写的一些行为:
1)仅当被写操作编辑时一行记录会被锁定
当一条更新的命令更新一行是,这个事务就会只获得这一行的锁。通过锁定在表中的这一条数据层次面
,这个数据库会很小的争夺对这个共享数据来说。正常情况下,数据库不会逐渐升级为对这个块的行锁
或是到一个表锁的等级。
2)只能在同一时间对一个数据块进行写入:
如果一个事务编辑表中的一行记录,那么这个行锁就会阻止其他事务同时对同一行的元组进行编辑。
3)读永远不会妨碍写
因为读一行数据不会进行对它枷锁,另一个事务可以同时对同一行进行编辑。这个当然除了select 。。
。from update这个语句之外,这个select是一个很特别的语句不会在它读的时候锁住一行数据。
4)写的时候不影响读
当一行数据被写入改变的时候,这个数据库会使用undo date去提供读取一致的行数据。
三)锁的使用
在一个单用户数据库中,锁就不需要了因为只有一个用户去编辑信息。然而,当多用户去访问和编辑数
据时,这个数据库必须提供一种方式去阻止去并发的编辑相同的数据。锁机制达到下面非常重要的数据
库的一些要求:
1)一致性
一个数据的session必须可见和改变数据但是不能被其他的session进行改变数据直到这个用户完成了操
作。
2)完整性
在正确修改序列时这个数据和数据结构必须反映所有操作的改变
在事务通过它们锁机制中oracle数据库提供了数据的并发性、一致性、完整性。锁是自动执行的不需要
用户操作。
当并发更新一行的时候,会说明需要什么要的锁。在下面的例子中,一个简单的web应用显示最终用户
的雇员邮箱和电话号码。这个应用使用update语句像下面这样编辑数据:
[sql]
eg:
update employees
set email=?,phone_number=?
where employee_id=?
and email=?
and phone_number=?
在update语句执行前,这个邮箱和电话号码值都是where字句之前的,没有对指定employee编辑之前的值
。这个update确保这行记录在被应用最后读和显示给用户不会改变。通过这个方式,这个应用避免失去
update数据的问题,当一个用户查看时却别其他用户编辑了.(也就是说不会出现脏读的情况)。
当执行sql语句的时候oracle数据库会自动获得所需要的锁。例如,当一个数据库允许一个会话去编辑一
个数据,这个会话必须首先锁定这个数据。这个锁能够给这个session排斥其他的事务对这个数据进行锁
定并修改,直到这个锁被释放掉。
因为这个锁的机制,数据库被事务控制联系紧密,应用开发者都会需要定义一些事务的特性,然后数据
库会自动的管理锁机制。用户从来不需要锁定许多明确的资源,当然了oracle数据库也允许用户手动去
锁定一些资源。
四)锁的模式
oracle数据自动使用最底的锁应用等级限制去最大程度上提供更高的并发性和数据的性。限制越低,就
能更好的提供数据被其他用户所访问。相反越高的限制等级就会限制其他用户事务获取他们所需要的数
据。
oracle数据库在多用户数据库中使用两中类型的锁(数据库可以使用startup restrict命令启动到一个
特权模式下,在该模式下只用特定权限的用户才可以访问数据库)
1)排他锁模式
在这种模式下阻止数据被共享。当一个事务编辑数据的时候就会获得一个排他锁。第一个事务锁定了一
个这个数据,那么只有他可以进行修改,其他用户如需在修改这个数据,那么必须等第一个事务修改完
成释放了排他锁。
2)共享锁模式
这个模式基于操作有关信息允许这个资源被共享。多个用户读取数据的时候会共享这个数据,持有共享
锁去一个需要获得排他锁的用户并发访问。几个事务能够在相同的数据资源中取得共享锁。
假设一个事务使用select 。。。for update 语句去选择单表的一行。那么这个事务会获得一个行级共
享排他锁。这个行锁允许其他的会话修改一些其他行,在这个表锁定的时候阻止会话去修改这个数据的
结构。因此数据库提供了很多语句去执行。
五)锁的转化和升级
当必要时,oracle会执行锁的转化操作。在锁的转化中,oracle会自动的转换一个表锁从较低的限制到
一个较高的限制。
例如。假设一个事务对employee表执行一个select 。。。for update然后更新锁住的行。在这种情况下
数据库会自动转换从一个表的行级共享锁到一个表的行级排他锁。在这个事务中这个事务获得行级排他
锁来完成所有数据行的插入、更新或是删除操作。因为行锁获取的是最高的约束程度,因此没有其他锁
的转化被获得或是去执行。
锁的转化与锁的升级是不同的,锁的转化在许多锁从一个很低的粒度到一个很高的粒度重现。如果一个
用户在一个表中锁定了很多的行,然后一下数据库自动的升级这个行锁到一个这个行所属表锁。那么锁
的数量会变小,但是约束的程度会增大。
oracle数据库从来都不会升级锁。锁的升级很大程度上会发生思锁。建设一个系统试着为了事务1升级锁
是不可行的因为这个锁被事务2持有了。这时当事务2也请求同意个数据被升级一个锁的时候死锁就产生
了。
六)锁的持续
当像一个事务不在需要这个资源这种事件发生的时候,oracle数据库会自动的释放锁。在大多数情况下
,在事务持续期间oracle数据库会通过事务的语句持有相应的锁。这些锁阻止并发事务的相互干啥,如
可能产生的脏读、不可重复读、和幻想读情况。
========