1.Oracle工作的特点
多用户并发,在一个时间点会有多个用户试图操作同一个资源
2.如何保护数据结构不被破坏
串行化
3.在满足串行化的前提下,如何将并发性提升到最大
通过使用队列enqueue,闩latch和锁lock
enqueue是Oracle使用的另一种锁定机制,它更加复杂,允许几个并发进程不同程度地共享某些资源。
latch是一个低级别的,轻量级的锁,获得和释放的速度都很快,
通过串行机制,保护共享内存,微妙级
通常用最低层的汇编指令实现
lock可能持续很长时间,通过使用队列,先进先出的方式实现
先获得latch,得到对内存块的操作权,再对表/行加lock,如果该对象已被加lock,就进入enqueue,等待。
4.latch
是ORACLE中的一种特殊锁,用于顺序访问内部系统结构。当事务需向缓冲区写入信息时,
为了使用此块内存区域,ORACLE首先必须取得这块内存区域的闩锁,才能向此块内存写入信息。
latch位于SGA的固定区域fixed area
shared pool,redo buffer和db buffer cache都需要latch,例如:
shared pool latch
checkpoint queue latch
cache buffers lru chain Latch
redo copy latch
redo allocation latch
Latch是用于保护SGA区中共享数据结构的一种串行化锁定机制。
10g前,latch获取一般在微秒级
从10g开始,引用了一种新机制,
mutex机制,互斥机制
mutex get: 30-35个指令, 大小占用16字节
latch: 150-200个指令,大小占用112字节
_kks_use_mutex_pin (true,false)
mutex机制替代library cache latch和library cache pin等机制.
何时需要latch
当一个进程准备访问SGA中的数据结构时,它就需要获得一个latch。
当进程获得latch后,它将一直持有该latch直到它不再使用此数据结构,
这时latch才会被释放。可通过latch名称来区分它所保护的不同数据结构。
怎么工作
Oracle使用元指令对latch进行操作, 当所需的latch已被其他进程持有时,
执行指令进程将停止执行部分指令,直到该latch被释放为止。
从根本上讲,latch防止并发访问共享数据结构,
由于设置和释放latch的指令是不可分割的,操作系统就可以
保证只有一个进程获得latch,又由于这只是单条指令,所以执行速度很快。
latch被持有的时间是很短,而且提供了当持有者不正常中断时的清除机制,
该清除工作是由Oracle后台进程PMON来完成的。
什么导致latch冲突
Latch保护SGA中的数据结构被多个用户同时访问,
如果一个进程不能立即得到所需latch,它就必须等待,
这就导致了CPU的额外负担和系统的速度降低。
额外的CPU使用是进程‘spining’导致的,
‘spining’是指进程定时地重复尝试获取latch,
在连续两次之间,进程处于休眠状态,
在得到latch之前,
spining过程将重复进行下去。
如何标识内部latch的冲突
v$latch表的每一行包括了对不同类型latch的统计,每一列反映了不同类型的latch请求的活动情况。
不同类型的latch请求之间的区别在于,当latch不可立即获得时,请求进程是否继续进行。
按此分类,latch请求的类型可分为两类:
willing-to-wait和immediate。
Willing-to-wait : 是指如果所请求的latch
不能立即得到,
请求进程将等待一很短的时间后再次发出请求。进程一直重复此过程直到得到latch。
Immediate:是指如果所请求的latch不能立即得到,请求进程就不再等待,而是继续执行下去。
在v$latch中的以下字段反映了Willing-to-wait请求:
GETS---成功地以Willing-to-wait请求类型请求
一个latch的次数。
MISSES---初始以Willing-to-wait请求类型请求
一个latch不成功的次数。
SLEEPS---初始以Willing-to-wait请求类型请求
一个latch不成功后,进程等待获取latch的次数。
在v$latch中的以下字段反映了Immediate类请求:
IMMEDIATE_GETS---以Immediate请求类型成功地获得一个latch的次数。
IMMEDIATE_MISSES---以Immediate请求类型请求
一个latch不成功的次数。
5.Enqueue
Enqueue是Oracle使用的另一种锁定机制,它更加复杂,允许几个并发进程不同程度地共享某些资源。
任何可被并发使用的对象均可使用enqueue加以保护。一个典型的例子是表的锁定,
我们允许在一个表上有不同级别的共享。与latch不同之处在于,enqueue是使用操作系统特定的锁定机制,
一个enqueue允许用户在锁上存贮一个标记,来表明请求锁的模式。操作系统lock manager跟踪所有被锁定的资源,
如果某个进程不能获取它所请求的那种锁,操作系统就把请求进程置于一个等待队列中,该队列按FIFO原则调度,
而在latches中是没有象enqueue中排序的等待队列,latch等待进程要么使用定时器来唤醒和重试,
要么spin(只用于多处理器情况下)。
v$session_wait:
p1: 锁类型和模式
p2: 锁ID1,以十进制表示的enqueue名称的ID1
p3: 锁ID2,以十进制表示的enqueue名称的ID2
通过查询v$lock可以获取锁的相关信息,
type:锁类型
ID1:锁ID1
ID2:锁ID2
session1,sqlplus
scott/tiger@hh update emp set ename='';
session2,sqlplus
scott/tiger@hh update emp set ename='';
session3,sqlplus
sys/oracle@hh as sysdba
select type, id1, id2,
decode(request,0,'Holder ','Waiter: ')||sid "session"
from v$lock
where (id1,id2,type) in
(select id1,id2,type from v$lock where request>0)
order by id1,request
在实例级,通过查询v$sysstat中的enqueue waits统计信息和StatsPack中的statistics部分可以诊断该事件实际发生的等待次数:
select * from v$sysstat where name='enqueue waits'
通过查询v$enqueue_stat可以诊断是哪些enqueue导致了等待:
select * from v$enqueue_stat where total_wait#>0
基于不同的锁类型有不同的解决方法。
TX Transaction Lock: 通常是由于应用的原因造成锁等待。
TM DML Enqueue: 通常是由于应用原因,部分是因为在外键约束上没有建立索引导致的。
ST Space Management Enqueue: 通常是由于过多的空间管理
(比如因为extent过小,导致extent的频繁分配/大量的排序导致临时段的分配)而产生的。
6.lock
表级锁
行级锁
ORACLE里锁有以下几种模式:
0:none
1:null 空
2:Row-S 行共享(RS):共享表锁
3:Row-X 行专用(RX):用于行的修改 exclusive
4:Share 共享锁(S):阻止其他DML操作
5:S/Row-X 共享行专用(SRX):阻止其他事务操作
6:exclusive 专用(X):独立访问使用
(1).锁的基本概念
为了存取共享对象时的正确性
基本的锁类型有:排他锁eXclusive lock X锁
共享锁Share lock S锁
X锁:若事务T对数据D加 X lock,则其他任何事务都不能再对D加任何类型的锁,直至T释放该锁。
一般要求在修改数据前要向该数据加X锁,所以该锁也称写锁。
S锁: 若事务T对数据D加 S lock,则其他任何事务都只能再对D加S锁,不能加X锁,直至T释放该锁。
一般要求在读取数据前要向该数据加S锁,所以该锁也称读锁。
(2).oracle多粒度lock机制
根据保护对象的不同,Oracle Lock可以分为以下几大类:
DML Lock(data lock,数据锁): 用于保护数据的完整性。DML锁有2个层次:行级锁和表级锁。
DDL Lock(dictionary lock,字典锁): 用于保护数据库对象的结构(例如表 视图 索引的结构定义)
internal lock和latch(内部锁与闩): 保护数据库内部结构
2.1 TX锁 transaction
transaction锁(事务锁,行级锁)
运行insert, update, delete,selec ... for update时,获得一个TX锁,直至该事务结束,即commit/rollback,该锁才释放;
被加锁的可以是一行或多行
在每行数据上,都有一个标志位来表示该行是否被锁定。
加的是X锁,oracle在数据行上没有S锁。
Oracle在每个块block的头部,保留有一个叫做ITL(Interested Transaction List)(相关事务列表)的结构,
每当一个事务要修改(或select for update)块中行时,它都需要将自己的事务标识记录在ITL的一项(即slot)中,
ITL slot 事务槽
而被其修改(或select for update)的行的行首的锁标识字节(lock bytes),记录事务在ITL中所占用的项(如1,2,3等)。
其实,未提交事务所占用的ITL slot与行首的lock bytes一起构成了对数据行的隐式封锁。
数据块中的ITL项数取决于initrans和maxtrans这两个参数。一般一项占用24字节。
行级锁(TX锁)
update employee set last_name='xkj' where exployee_id=100;
1、Oracle对该SQL语句进行解析,找到exployee_id为100的记录所在的数据块(假设为58号数据块),
并找到一个可用的undo数据块,将last_name列上被更新前的旧值放入该undo数据块
2、在58号数据块的头部分配一个ITL槽,在该槽里存放当前的是事务ID、SCN号、所使用的undo数据块的地址,
以及未提交的标记等信息
3、在58号数据块中,找到被更新的数据行,在数据行头部设置一个锁定标记,
并在头部记录当前事务所使用的ITL槽号,做完这些工作
4、控制权交给用户,该锁定说明当前用户在被修改的数据行上已经添加了X锁
如果这时,另一个用户B也对exployee_id为100的记录进行修改,则其过程和上面描述一样,
只不过B在对数据行的头部设置锁定标记的时候,发现该数据行头部已经有一个锁定标记了,
说明该记录已经添加了X锁,于是用户B必须等待,等待X锁被释放。
锁定一条记录,并不影响其他用户对该记录的读取,例如
如果用户发出一条SQL语句,检索exployee_id为100的记录信息,
这时服务器进程发现被检索的记录有锁定标记,说明该记录已经被其他用户修改了,
但是还没有提交。于是根据数据行头部记录到ITL槽的号码,在数据块头部找到ITL槽,
并根据其中记录的undo数据块的地址,找到该undo数据块,将其中所保存的改变前的旧值取出来,
并构建CR(consistent read 读一致性)块,根据CR块的内容,将用户所需要的信息进行返回。
对于Oracle来说,行级锁只有X锁定模式,没有S锁定模式,更新数据行,只是锁定被更新的数据行
2.2 TM锁(表级锁) DML
(1)意向锁的引出
为了提高效率,在表级加意向锁,就不用逐行检查每行的锁标志位了。
加时自上而下,解锁时自下而上。
(2)意向锁的类型
意向共享锁(intent share lock,IS): 如果要对一个数据库对象加S锁,首先要对其上级节点加IS锁,表示它的后缀节点拟(意向)加S锁。
意向排他锁(intent exclusive lock,IX): 如果要对一个数据库对象加X锁,首先要对其上级节点加IX锁, 表示它的后缀节点拟(意向)加X锁。
共享意向排他锁(shared intent exclusive lock,SIX): 如果要对一个数据库对象加SIX锁, 表示要对它(表)加S锁,再对下级(行)加IX锁,即SIX=S+IX。
这样,数据库对象上所加的锁类型就可能有5种,即S、X、IS、IX、SIX。
(3)TM锁(表级锁)
oracle的DML锁(数据锁)正是采用了上面提到的多粒度锁方法,其行级锁虽然只有一种(即X锁),
但其TM锁(表级锁)类型共有5种:S锁、X锁、行级共享锁RS锁、行级排他锁RX锁、共享行级排他锁SRX锁,与
上面提到的S、X、IS、IX、SIX相对应。
需要注意的是,由于Oracle在行级只提供X锁,所以与RS锁(select for update)对应的行级锁也是X锁(但是该行实际上
还没有被修改),这与理论上的IS锁是有区别的。
表级锁
会话A(scott)发出了
delete from t where rownum=1;
select sid from v$mystat where rownum=1;
141
当A还没有提交之前,
另外一个会话B(scott)发出下面的语句
drop table t;
报 ORA-00054: resource busy
由于会话A还没有提交所做的事务,该事务还没有结束,其他会话不能删除该表,
否则A所发出的事务就无法正常结束,为了阻止会话B的删除操作,我们能够想到的最直观的方法是
在执行删除表的命令以前,先依次检查T表里的每一条记录,
查看每一条数据行的头部是否存在锁定标记,如果是,则说明正有当前事务在更新表,
删除表的操作必须等待
显然这样存在很大的性能问题
实际上,当我们在对T表的数据进行更新时,不仅会在数据行的头部记录行级锁,
而且还会在表的级别上添加一个表级锁,这样可以提高锁管理的性能
select * from v$lock where sid=141
TYPE LMODE
TM 3 表级锁
TX 6 行级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
3 24 458 52800 3
select * from v$rollname where usn=3 USN: Rollback (undo) segment number
3 _SYSSMU3$
从而知道被删除的这条记录目前在回滚段SYSSMU3$里
表级锁共有5种模式
行共享 (ROW SHARE) – 禁止排他锁定表
行排他(ROW EXCLUSIVE) – 禁止使用排他锁和共享锁
共享锁(SHARE)
锁定表,仅允许其他用户查询表中的行
禁止其他用户插入、更新和删除行
多个会话可以同时在同一个表上应用此锁
共享行排他(SHARE ROW EXCLUSIVE) – 比共享锁更多的限制,禁止使用共享锁及更高的锁
排他(EXCLUSIVE) – 限制最强的表锁,仅允许其他用户查询该表的行。禁止修改和锁定表
lock table tab_name in row share mode;
lock table tab_name in row exclusive mode;
lock table tab_name in share mode;
lock table tab_name in share row exclusive mode;
lock table tab_name in exclusive mode;
1、行共享锁(ROW SHARE) RS锁 lmode:2, Row-S 行共享(RS):共享表锁
在表上添加了一个行级的共享锁,这里面的select可以是多条记录,往往是多条记录。
用户在执行select for update的时候,不希望其他用户对这些记录进行更新,经常发出这些命令。
查询完成以后,发出rollback命令解锁
表上添加了RS锁以后,不允许其他事务对相同的表添加X锁,但是允许其他事务通过DML对
表里面的其他数据进行修改,也允许添加行级排他锁
不允许对锁定的数据进行修改。
允许对没有锁定的数据进行修改
select * from emp where empno=7369 for update;
select * from v$lock where sid=139
TYPE LMODE
TM 3 表级锁
TX 6 行级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
1 15 383 51148 3
由于Oracle在行级只提供X锁,所以与RX锁(select for update)对应的行级锁
也是X锁(但是该行实际上还没有被修改)
sid: 316
lock table emp in row share mode; (commit/rollback取消此锁)
select * from v$lock where sid=316
TYPE LMODE
TM 2 表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 2
不允许其他事务对表添加X锁
另一会话:lock table emp in exclusive mode;
等待
select * from v$lock where sid=142
TYPE LMODE REQUEST
TM 0 6 X表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 0
2、行级排他锁(Row exclusive)RX锁 lmode:3
当我们进行DML时,会自动在被更新的表上添加RX锁,也可以执行LOCK命令显式的在表上添加RX锁
delete from emp; (commit/rollback取消此锁)
select * from v$lock where sid=159 52915:MLOG$_EMP 51148:EMP 51146:DEPT
SID ID1 ID2 TYPE LMODE
139 51146 0 TM 2 表级锁
139 51148 0 TM 3 表级锁
139 52915 0 TM 3 表级锁
139 393262 444 TX 6 行级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
6 46 444 52915 3
6 46 444 51148 3
6 46 444 51146 2
允许其他事务通过DML语句修改相同表里的其他数据行
允许使用lock命令对表添加RX锁定
另一会话:lock table emp in row exclusive mode;
select * from v$lock where sid=139
TYPE LMODE
TM 3 表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 3
不允许其他事务对表添加X锁
另一会话:lock table emp in exclusive mode;
等待
select * from v$lock where sid=142
TYPE LMODE REQUEST
TM 0 6 表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 0
3.共享锁(SHARE) S锁 lmode:4
阻止其他会话对该表的DML操作
本会话可以对该表DML,不允许其他会话更新表
多个会话可以同时在同一个表上应用此锁
lock table emp in share mode; (commit/rollback取消此锁)
select * from v$lock where sid=139
TYPE LMODE
TM 4 S表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 7 0 51148 4
139:delete from emp where empno=7369; ok
142: delete from emp where empno=7788; no
4.共享行排他(SHARE ROW EXCLUSIVE) lmode:5 SRX锁 – 比共享锁更多的限制,禁止使用共享锁及更高的锁
lock table emp in share row exclusive mode;
select * from v$lock where sid=139
TYPE LMODE
TM 5 SRX表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 5
139:delete from emp where empno=7369; ok
135: delete from emp where empno=7788; no
select * from emp; ok
lock table emp in share mode; 等待
5.排他(EXCLUSIVE) lmode:6 – 限制最强的表锁,仅允许其他用户查询该表的行。禁止修改和锁定表
lock table emp in exclusive mode;
select * from v$lock where sid=139
TYPE LMODE
TM 6 X表级锁
select * from v$locked_object
xidusn xidslot xidsqn object_id locked_mode
0 0 0 51148 6
139:delete from emp where empno=7369; ok
135: delete from emp where empno=7788; no
select * from emp; ok
lock table emp in share mode; 等待
2.3 Oracle多粒度锁机制的监控
v$lock 列出当前系统持有的或正在申请的所有锁的情况
记录了当前session已经获得的锁定以及正在请求的锁定的信息。
其中比较重要的字段包括SID说明session的ID号、TYPE说明锁定级别,
主要关注TX和TM、LMODE说明已经获得的锁定的模式,以数字编码表示、
REQUEST说明正在请求的锁定的模式,以数字编码表示。BLOCK说明是否
阻止了其他用户获得锁定,大于0说明是,等于0说明否。
v$locked_object 列出了当前系统中哪些对象正被锁定
记录了当前已经被锁定的对象的信息。其中比较重要的字段包括XIDUSN表示当前事务
使用的回滚段的编号、XIDSLOT说明该事务在回滚段头部的事务表中对应的记录编号、
XIDSQN说明序列号、OBJECT_ID说明当前被锁定的对象的ID号,可以根据该ID号到
dba_objects里查找被锁定的对象名称、LOCKED_MODE说明锁定模式的数字编码。
v$session 如果当前的某个会话因为某数据行被阻塞,该数据行的位置信息可以通过
row_wait_obj#(该行所在的数据对象标识)、row_wait_file#(该行所在的数据文件标识)、
row_wait_block#(该行所在的数据块标识)、row_wait_row#(该行在数据块中的位置标识)等字段获得。
v$transaction
记录了当前每个活动事务(也就是还没有提交或者回滚的事务)的信息。
其中比较重要的字段包括XIDUSN表示当前事务使用的回滚段的编号、XIDSLOT说明该事务
在回滚段头部的事务表中对应的记录编号(也可以叫做槽号)、XIDSQN说明序列号、
STATUS说明该事务是否为活动的。
v$enqueue_lock
该视图中包含的字段以及字段含义与v$lock中的字段一模一样。
只不过该视图中只显示那些申请锁定,但是无法获得锁定的session信息。
其中的记录按照申请锁定的时间先后顺序排列,先申请锁定的session排在前面,
排在前面的session将会先获得锁定。
10g
create or replace view view_lock as
select sid session_id,
decode(type,
'MR', 'Media Recovery',
'RT', 'Redo Thread',
'UN', 'User Name',
'TX', 'Transaction',
'TM', 'DML',
'UL', 'PL/SQL User Lock',
'DX', 'Distributed Xaction',
'CF', 'Control File',
'IS', 'Instance State',
'FS', 'File Set',
'IR', 'Instance Recovery',
'ST', 'Disk Space Transaction',
'TS', 'Temp Segment',
'IV', 'Library Cache Invalidation',
'LS', 'Log Start or Switch',
'RW', 'Row Wait',
'SQ', 'Sequence Number',
'TE', 'Extend Table',
'TT', 'Temp Table',
type) lock_type,
decode(lmode,
0, 'None', /* Mon Lock equivalent */
1, 'Null', /* N */
2, 'Row-S (SS)', /* L */
3, 'Row-X (SX)', /* R */
4, 'Share', /* S */
5, 'S/Row-X (SSX)', /* C */
6, 'Exclusive', /* X */
to_char(lmode)) mode_held,
decode(request,
0, 'None', /* Mon Lock equivalent */
1, 'Null', /* N */
2, 'Row-S (SS)', /* L */
3, 'Row-X (SX)', /* R */
4, 'Share', /* S */
5, 'S/Row-X (SSX)', /* C */
6, 'Exclusive', /* X */
to_char(request)) mode_requested,
to_char(id1) lock_id1, to_char(id2) lock_id2,
ctime last_convert,
decode(block,
0, 'Not Blocking', /* Not blocking any other processes */
1, 'Blocking', /* This lock blocks other processes */
2, 'Global', /* This lock is global, so we can't tell */
to_char(block)) blocking_others
from v$lock
0、Waiting
1、NULL,可以某些情况下,如分布式数据库的查询会产生此锁。
2、SS,表结构共享锁
表结构共享+加上部分数据共享.虽然有人说,ORACLE里,数据没有S状态,但我还是愿意这样理解:
第1个S代表表结构共享,第2个代表表里的数据共享. 你可以想象一下,当往子表里增加纪录时,
主表的相关主键是不是得处于共享模式.
3、SX,表结构共享锁+被操作的记录的排它锁, 用于DML操作,第1个S代表表结构共享,第2个代表表里被操作的数据独占.
4、S, 表结构共享锁+所有记录共享锁, 代表表结构+表里的数据都是处于共享模式.当对表创建索引时,在创建期间,表处于这种模式.
5、SRX 表结构共享锁+所有记录排它锁, SRX=S(4)+SX(3),
6、X 表结构排它锁+所有记录排它锁
lmode
0 - none Waiting
1 - null (NULL)
2 - row-S (RS)
3 - row-X (RX)
4 - share (S)
5 - S/Row-X (SRX)
6 - exclusive (X)
(3).示例
se1:sqlplus
scott/tiger@olit1 select * from dept for update;
se0:sqlplus
sys/oracle@olit1 as sysdba
select * from v$locked_object where session_id=105 XIDUSN:Undo segment number XIDSLOT:Slot number
xidusn xidslot xidsqn object_id locked_mode XIDSQN:Sequence number
7 30 442 51146 3
select * from v$session where sid=105
select * from v$lock where sid=105 type: TM - DML enqueue,TX - Transaction enqueue
sid type id1 id2 lmode id1: Lock identifier #1
105 TM 51146 0 3 id2: Lock identifier #2
105 TX 458782 442 6
select trunc(458782/65536) xidusn, mod(458782,65536) xidslot from dual;
7 30
即:当type是TX,id1是该事务所占用的undo段号与事务槽号的组合,id2是该槽被重用的次数,
实际上,这3个值唯一地标识一个事务,即transaction id,这3个值也可从v$transaction中查到。
v$transaction.addr Address of the transaction state object
v$lock.addr Address of lock state object
se2:sqlplus
scott/tiger@olit1 update dept set loc='loc' where deptno=20;
该语句被阻塞
se0:select * from v$locked_object where session_id=130 XIDUSN:Undo segment number XIDSLOT:Slot number
xidusn xidslot xidsqn object_id locked_mode XIDSQN:Sequence number
0 0 0 51146 3
select * from v$session where sid=130
select * from v$lock where sid=130 type: TM - DML enqueue,TX - Transaction enqueue
sid type id1 id2 lmode request id1: Lock identifier #1
130 TM 51146 0 3 0 id2: Lock identifier #2
130 TX 458782 442 0 6
dept上有2个row-X (SX)锁,还没有为session_id=130分配undo段,
申请一个exclusive (X)锁
下面将se1的事务回滚,解除对se2的阻塞,再观察。
se1:rollback;
se0:select * from v$locked_object where session_id=130 XIDUSN:Undo segment number XIDSLOT:Slot number
xidusn xidslot xidsqn object_id locked_mode XIDSQN:Sequence number
5 35 539 51146 3
select * from v$session where sid=130
select * from v$lock where sid=130 type: TM - DML enqueue,TX - Transaction enqueue
sid type id1 id2 lmode request id1: Lock identifier #1
130 TM 51146 0 3 0 id2: Lock identifier #2
130 TX 327715 539 6 0
select trunc(327715/65536) xidusn, mod(327715,65536) xidslot from dual;
5 35
可以看到se1的事务所持有的锁已经释放,系统为se2的事务分配了undo段。
再将se2的事务进行回滚
se2:rollback;
se0:
select * from v$locked_object where session_id in (105,130)
no rows
select * from v$lock where sid in (105,130)
no rows
锁全被释放
ora错误 60 600
7.死锁 dead lock【通过让第一个用户rollback来解除死锁】在alert文件中查询60即可
当两个事务相互等待对方释放资源时,就会形成死锁
Oracle会自动检测死锁,并通过结束其中的一个事务来解决死锁
T1,LOCK(O1),
T2,LOCK(O2),
T1,LOCK(O2),
T2,LOCK(O1),
8. DDL锁定
在执行DDL命令之前,Oracle会自动添加一个隐式提交命令,然后执行具体的DDL命令,
在DDL命令执行结束之后,还会自动添加一个隐式提交命令。
实际上,Oracle在执行DDL命令时,都会将其转换为对数据字典表的DML操作。
比如我们发出创建表的DDL命令时,Oracle会将表的名称插入数据字典表tab$里,
同时将表里的列名以及列的类型插入col$表里等。
因此,在DDL命令中需要添加隐式的提交命令,从而提交那些对数据字典表的DML操作。
即使DDL命令失败,它也会发出提交命令。
当我们发出DDL命令时,会自动在被处理的对象上添加DDL锁定,
从而防止对象被其他用户所修改。当DDL命令结束以后,则释放DDL锁定。
我们不能显式地请求一个DDL锁定,只有当对象结构被修改或者被引用时,
才会在对象上添加DDL锁定。比如创建或者编译存储过程时会对引用的对象添加DDL锁定。
在创建视图时,也会对引用的表添加DDL锁定等。
DDL锁定具有以下三种类型
1)、排他的DDL锁定 Exclusive DDL Lock
大部分的DDL操作都会在被操作的对象上添加排他的DDL锁定,
从而防止在DDL命令期间,对象被其他用户修改,当对象添加了
排他的DDL锁定以后,该对象上不能再添加任何其他的DDL类型,
如果是对表进行DDL,则其它进程也不能修改表里的数据
2)、共享的DDL锁定 Shared DDL Lock
用来保护被DDL的对象不被其他用户进程更新,但是允许其它进程在对象上
添加共享的DDL锁定,如果是对表进行DDL命令,则其它进程可以同时修改表里的数据
例如create view命令创建视图的时候,在视图中所引用的表上添加的就是共享的DDL锁定,
创建视图的时候,其他用户不允许修改表结构,但是可以更新数据
3)、可打破的解析锁定Breakable Parsed Lock
在shared pool里缓存的SQL游标、PL/SQL代码都会获得引用对象上的解析锁定,
如果我们发出DDL命令修改了某个表的结构时,该对象相关的、位于shared pool里
的解析锁定就会被打破,从而导致引用了该对象的SQL游标或者PL/SQL程序代码全都失效,
下次再执行相同的SQL语句时,需要重新解析,这就是所谓的SQL语句的reload,
可打破的解析锁定不会阻止其他的DDL锁定,如果发生与解析锁定相冲突的DDL锁定,
则解析锁定也会被打破。
select * from dba_ddl_locks where session_id=135
会话135:
alter table t add ( b number);
alter table t drop column b ;
执行太快,看不到
create or replace procedure pt
is
i number :=0;
begin
loop
i:=i+1-1;
end loop;
end;
/
execute pt;
另一会话:sid=139
alter procedure pt compile;
另一会话:
select * from dba_ddl_locks where session_id=135
135 SCOTT PT Table/Procedure/Type Null None
select * from dba_ddl_locks where session_id=139
139 SCOTT PT Table/Procedure/Type Exclusive None
9. dbms_lock包
-- create demo table
CREATE TABLE lock_test (
action VARCHAR2(10),
when TIMESTAMP(9));
GRANT insert ON lock_test TO public;
CREATE OR REPLACE PACKAGE lock_demo IS
v_lockname VARCHAR2(12) := 'control_lock';
v_lockhandle VARCHAR2(200);
v_result PLS_INTEGER;
-- obtain a lock
PROCEDURE request_lock(p_ltype INTEGER, p_retval OUT INTEGER);
-- release an existing lock
PROCEDURE release_lock(p_retval OUT INTEGER);
-- view the stored handle
FUNCTION see_handle RETURN VARCHAR2;
-- decode lock request
FUNCTION decode_req(p_result PLS_INTEGER) RETURN VARCHAR2;
-- decode lock release
FUNCTION decode_rel(p_result PLS_INTEGER) RETURN VARCHAR2;
END lock_demo;
/
CREATE OR REPLACE PACKAGE BODY lock_demo IS
PROCEDURE request_lock(p_ltype IN INTEGER, p_retval OUT INTEGER) IS
BEGIN
IF v_lockhandle IS NULL THEN
dbms_lock.allocate_unique(v_lockname, v_lockhandle);
p_retval := dbms_lock.request(v_lockhandle, p_ltype);
END IF;
END request_lock;
------------------------------------------------------------
PROCEDURE release_lock(p_retval OUT INTEGER) IS
BEGIN
IF v_lockhandle IS NOT NULL THEN
p_retval := dbms_lock.release(v_lockhandle);
END IF;
END release_lock;
------------------------------------------------------------
FUNCTION see_handle RETURN VARCHAR2 IS
BEGIN
IF v_lockhandle IS NOT NULL THEN
RETURN v_lockhandle;
ELSE
RETURN 'Not Allocated';
END IF;
END see_handle;
------------------------------------------------------------
FUNCTION decode_req(p_result PLS_INTEGER) RETURN VARCHAR2 IS
retval VARCHAR2(20);
BEGIN
SELECT DECODE(p_result,0,'Success',1,'Timeout',2,'Deadlock',
3,'Parameter Error',4,'Already owned',5,'Illegal Lock Handle')
INTO retval
FROM dual;
RETURN retval;
END decode_req;
------------------------------------------------------------
FUNCTION decode_rel(p_result PLS_INTEGER) RETURN VARCHAR2 IS
retval VARCHAR2(20);
BEGIN
SELECT DECODE(p_result,0,3, 'Parameter Error',4, 'Already owned',
5, 'Illegal Lock Handle')
INTO retval
FROM dual;
RETURN retval;
END decode_rel;
------------------------------------------------------------
END lock_demo;
/
GRANT execute ON lock_demo TO public;
set serveroutput on
-- get an exclusive lock in the current session (Session 1)
DECLARE
s VARCHAR2(200);
BEGIN
lock_demo.request_lock(6, s);
dbms_output.put_line(s);
END;
/
select * from v$lock where sid in (135)
type lmode
UL 6
'UL', 'PL/SQL User Lock'
/* Two session request a shared lock (ss_mode).
The shared lock cannot be acquired because session 1 holds an exclusive lock.
Execution will stop on the request until the the exclusive lock is released. */ Session 2 Session 3
Session 2, scott,sid=139
set serveroutput on
DECLARE
s VARCHAR2(200);
BEGIN
lock_demo.request_lock(dbms_lock.ss_mode, s);
dbms_output.put_line(s);
INSERT INTO scott.lock_test
(action, when)
VALUES
('started', SYSTIMESTAMP);
dbms_lock.sleep(5);
INSERT INTO scott.lock_test
(action, when)
VALUES
('ended', SYSTIMESTAMP);
COMMIT;
END;
/
等待
select * from v$lock where sid in (139)
type lmode request
UL 0 2
Session 3, scott, sid=137
set serveroutput on
DECLARE
s VARCHAR2(200);
BEGIN
lock_demo.request_lock(
dbms_lock.ss_mode, s);
dbms_output.put_line(s);
INSERT INTO lock_test
(action, when)
VALUES
('started', SYSTIMESTAMP);
dbms_lock.sleep(5);
INSERT INTO lock_test
(action, when)
VALUES
('ended' , SYSTIMESTAMP);
COMMIT;
END;
/
等待
select * from v$lock where sid in (137)
type lmode request
UL 0 2
-- Session 1 releases its lock
DECLARE
s VARCHAR2(200);
BEGIN
lock_demo.release_lock(s);
dbms_output.put_line(s);
END;
/
-- Execution resumes when the exclusive lock is released
SELECT TO_CHAR(when,'dd.mm.yyyy hh24:mi:ss'), action
FROM lock_test
ORDER BY when;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/20670907/viewspace-742563/
,如需转载,请注明出处,否则将追究法律责任。