共计 5833 个字符,预计需要花费 15 分钟才能阅读完成。
问题如下:
SQL> conn scott/scott@vm_database
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0
Connected as scott
………………
SQL> drop table student;
drop table student
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效
=========================================================
解决方法如下:
=========================================================
SQL> select session_id from v$locked_object;
SESSION_ID
———-
142
SQL> SELECT sid, serial#, username, oSUSEr FROM v$session where sid = 142;
SID SERIAL# USERNAME OSUSER
———- ———- —————————— ——————————
142 38 SCOTT LILWEN
SQL> ALTER SYSTEM KILL SESSION ‘142,38’;
System altered
SQL> conn scott/scott@vm_database
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0
Connected as scott
SQL> drop table student;
Table dropped
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 发生阻塞的唯一情况就是用户拥有一个建有主键约束的表。当 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 锁分类表
表 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、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
1. 关于 V$lock 表和相关视图的说明
Column Datatype Description
ADDR RAW(4 | 8) Address of lock state object
KADDR RAW(4 | 8) Address of lock
SID NUMBER Identifier for session holding or acquiring the lock
TYPE VARCHAR2(2) Type of user or system lock
The locks on the user types are obtained by user applications. Any process that is blocking others is likely to be holding one of these locks. The user type locks are:
TM – DML enqueue
TX – Transaction enqueue
UL – User supplied
– 我们主要关注 TX 和 TM 两种类型的锁
–UL 锁用户自己定义的,一般很少会定义,基本不用关注
– 其它均为系统锁,会很快自动释放,不用关注
ID1 NUMBER Lock identifier #1 (depends on type)
ID2 NUMBER Lock identifier #2 (depends on type)
— 当 lock type 为 TM 时,id1 为 DML-locked object 的 object_id
— 当 lock type 为 TX 时,id1 为 usn+slot,而 id2 为 seq。
– 当 lock type 为其它时,不用关注
LMODE NUMBER Lock mode 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)
– 大于 0 时表示当前会话以某种模式占有该锁,等于 0 时表示当前会话正在等待该锁资源,即表示该会话被阻塞。
– 往往在发生 TX 锁时,伴随着 TM 锁,比如一个 sid= 9 会话拥有一个 TM 锁,一般会拥有一个或几个 TX 锁,但他们的 id1 和 id2 是不同的,请注意
REQUEST NUMBER Lock mode in which the process requests 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)
– 大于 0 时,表示当前会话被阻塞,其它会话占有改锁的模式
CTIME NUMBER Time since current mode was granted
BLOCK NUMBER The lock is blocking another lock
0, ‘Not Blocking’,
1, ‘Blocking’,
2, ‘Global’,
– 该锁是否阻塞了另外一个锁
2. 其它相关视图说明
视图名 描述 主要字段说明
v$session 查询会话的信息和锁的信息。sid,serial#:表示会话信息。
program:表示会话的应用程序信息。
row_wait_obj#:表示等待的对象, 和 dba_objects 中的 object_id 相对应。
lockwait : 该会话等待的锁的地址, 与 v$lock 的 kaddr 对应.
v$session_wait 查询等待的会话信息。sid:表示持有锁的会话信息。
Seconds_in_wait:表示等待持续的时间信息
Event:表示会话等待的事件,锁等于 enqueue
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. 查询数据库中的锁
select * from v$lock;
select * from v$lock where block=1;
2. 查询被锁的对象
select * from v$locked_object;
3. 查询阻塞
查被阻塞的会话
select * from v$lock where lmode=0 and type in (‘TM’,’TX’);
查阻塞别的会话锁
select * from v$lock where lmode>0 and type in (‘TM’,’TX’);
4. 查询数据库正在等待锁的进程
select * from v$session where lockwait is not null;
5. 查询会话之间锁等待的关系
select a.sid holdsid,b.sid waitsid,a.type,a.id1,a.id2,a.ctime from v$lock a,v$lock b
where a.id1=b.id1 and a.id2=b.id2 and a.block=1 and b.block=0;
6. 查询锁等待事件
select * from v$session_wait where event=’enqueue’;
解决方案:
select session_id from v$locked_object; – 首先得到被锁对象的 session_id
SELECT sid, serial#, username, osuser FROM v$session where sid = session_id; – 通过上面得到的 session_id 去取得 v$session 的 sid 和 serial#,然后对该进程进行终止。
ALTER SYSTEM KILL SESSION ‘sid,serial’;
example:
ALTER SYSTEM KILL SESSION ’13, 8′;
更多 Oracle 相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-07/133614.htm