您的位置:首页 > 数据库 > Oracle

Oracle OCP笔记(18)并发与锁

2015-03-11 11:23 197 查看

Oracle OCP笔记(18)并发与锁

一.锁定机制

在任何多用户数据库应用程序中,最终免不了会出现两个用户希望同时使用同一行的情况。借助表和记录的锁定机制,可以实现并发访问的串行化。

二.共享锁与排他锁(share lock, exclusive lock)

排他锁:

在指定记录上请求排他锁的第一个会话会得到排他锁,其他请求对该记录进行写访问的会话则必须等待.虽然这行已通过锁定会话进行了更新,但是对其进行读访问是被允许的(而且经常会出现这种情况),并且这些读操作会涉及撤销数据的使用,从而确保读会话并不会看到任何未被提交的变化.

对于一行或一个表上的排他锁来说,每次只能有一个会话可以获得这个排他锁,不过许多会话可以同时获得相同对象上的共享锁。

共享锁

在一行上设置共享锁毫无意义,锁定一行的唯一目的就是不允许其他会话更改它。共享锁被置于整个表上。同时许多会话可以获得同一个表上的共享锁。

在一个表上放置共享锁的目的是为了防止另一个会话获得这个表上的排他锁(在已存在共享锁的情况下无法再获得排他锁).

在表上放置排他锁时需要执行DDL语句,如果其他人和会话已经在一个表上放置了共享锁,就无法修改某个对象的语句(例如删除这个表的一列).

为了在行上执行DML语句,当前会话必须获取待更改行上的排他锁以及包含这些行的表上的共享锁,如果另一个会话已经获取了待更改行上的排他锁,那么当前会话将被挂起,直至使用COMMIT或ROLLBACK命令解除锁定。如果另一个会话已经获取了表上的共享锁以及其他行上的排他锁,就不存在任何问题。

一个表上的排他锁也是允许的,但是,除非DDL语句要求这么做,默认锁定机制是不锁定整个表。

所有DML语句至少都需要两种锁定: 受影响记录上的排他锁,以及包含受影响记录的表上的共享锁。排他锁能够防止其他会话干预指定的行,而共享锁则能够阻止其他会话使用DDL语句修改表的定义。这两种锁定会被自动请求。如果某条DML语句在指定记录上无法获取所需的排他锁,那么这条语句会被挂起直至获得所需的排他锁。

执行DDL命令需要使用所涉及对象上的排他锁,只有在针对指定表的所有DML事务结束,且行上的排他锁以及表上的共享锁都被解除之后,才可以获得执行DDL命令所需的排他锁。任何DDL语句所需要的排他锁都是被自动请求的。但是,如果无法获取所需的排他锁(通常是因为其他会话已经获得用于DML语句的共享锁),那么DDL语句就会由于错误立即终止。

三.监视锁定争用.

-- 查看锁定的会话和锁定对象

select s.sid,s.serial#,s.lockwait,s.status,s.schemaname,s.machine,s.terminal,s.osuser,s.program,s.module,s.action,s.logon_time,

l.oracle_username,l.os_user_name,l.locked_mode,o.owner,o.object_name,o.object_type,o.status

from v$session s,

v$locked_object l,

dba_objects o

where s.sid = l.session_id

and l.object_id = o.object_id;

-- 查看阻塞与等待锁的会话

select * from dba_waiters;

-- 查看锁定的会话和锁定对象(阻塞的会话)

select s.sid,s.serial#,s.lockwait,s.status,s.schemaname,s.machine,s.terminal,s.osuser,s.program,s.module,s.action,s.logon_time,

l.oracle_username,l.os_user_name,l.locked_mode,o.owner,o.object_name,o.object_type,o.status,

'alter system kill session '||''''|| s.sid||','||s.serial#||''''||';' kill_session_sql

from v$session s,

v$locked_object l,

dba_objects o

where s.sid = l.session_id

and l.object_id = o.object_id

and s.sid in (select holding_session from dba_waiters);

-- 查看锁定的会话和锁定对象(阻塞的会话),RAC环境

select s.sid,s.serial#,s.lockwait,s.status,s.schemaname,s.machine,s.terminal,s.osuser,s.program,s.module,s.action,s.logon_time,

l.oracle_username,l.os_user_name,l.locked_mode,o.owner,o.object_name,o.object_type,o.status,

'alter system kill session '||''''|| s.sid||','||s.serial#||''''||';' kill_session_sql

from gv$session s,

gv$locked_object l,

dba_objects o

where s.sid = l.session_id

and l.object_id = o.object_id

and s.sid in (select holding_session from dba_waiters);

-- 查看正在执行的SQL语句(排除当前的语句)

select s.sid,s.serial#,s.lockwait,s.status,s.schemaname,s.machine,s.terminal,s.osuser,

s.program,s.module,s.action,s.logon_time,t.sql_id,t.piece,t.sql_text

from v$session s,

v$sqltext t

where s.sql_address = t.address

and s.sql_hash_value = t.hash_value

and s.status = 'ACTIVE'

and s.sid <> userenv('SID') --(select sid from v$mystat where rownum = 1)

order by s.sid,t.sql_id,t.piece;

-- 查看正在执行的SQL语句(排除当前的语句)

select s.sid,s.serial#,s.lockwait,s.status,s.schemaname,s.machine,s.terminal,s.osuser,

s.program,s.module,s.action,s.logon_time,a.sql_text,a.sql_fulltext

from v$session s,

v$sqlarea a

where s.sql_address = a.address

and s.sql_hash_value = a.hash_value

and s.status = 'ACTIVE'

and s.sid <> userenv('SID') --(select sid from v$mystat where rownum = 1)

order by s.sid

-- 杀掉长期锁定对象的会话

alter system kill session 'sid,serial#' immediate;

四.死锁(deadlock)

两个会话相互阻塞,这两个会话都被挂起,每个会话都在等待另一个会话释放锁定,这种场景被称为死锁(deadlock)。

死锁是由不合理的程序设计导致的,发生死锁问题的原因是程序试图获得锁定对象的顺序不一致导致的。数据库系统能自动检测到死锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: