9i10g11g编程艺术——锁和闩
来源:互联网 发布:php cookie能存多少 编辑:程序博客网 时间:2024/05/01 06:25
1、锁类型
oracle中主要有3中类型锁:
DML锁(DML lock):DML代表数据操作语言。一般来讲,这表示select、insert、update、merge和delete语句。DML锁机制允许并发执行数据修改。例如,DML锁可能是特定数据行上的锁,或者是锁定表中所有行的表级锁。
DDL锁(DDL lock):DDL代表数据定义语言,如create和alter语句等。DDL锁可以保护对象结构定义。
内部锁和闩:orange使用这些锁来保护其内部数据结构。闩(latch)是orange采用的一种轻量级的低级串行化设备,功能上类似于锁。不要被“轻量级”这个词搞糊涂或蒙骗了,你会看到,闩是数据库中导致竞争的一个常见原因。轻量级指的是闩的实现,而不是闩的作用。
2、DML锁
DML锁(DML lock)用于确保一次只有一个人能修改某一行,而且你正在处理一个表时别人不能删除这个表。在你工作时,oracle会透明程度不易的为你加这些锁。
2.1、TX锁
在oracle中,闩为数据的一个属性。oracle并没有一个传统的锁管理器,不会用锁管理器为系统中锁定的每一行维护一个长长的列表。不过,其他的许多数据库却是这样做的,因为对于这些数据库来说,锁是一种稀有资源,需要对锁的使用进行监视。使用的锁越多,系统要管理的方面就越多,所以在这些系统中,如果使用了“太多的”锁就会有问题。
oracle中的锁定过程如下所示。
(1)找到想锁定的那一行的地址。
(2)到达那一行。
(3)锁定这一行——在这行的位置,而非某个大列表。(如果这一行已经锁定,则等待锁住它的事务结束,除非使用了nowait选项。)
仅此而已。由于闩为数据的一个属性,oracle不需要传统的锁管理器。事务只是找到数据,如果数据还没有被锁定,则对其锁定。有意思的是,找到数据时,它可能看上去被锁住了,但实际上并非如此。在oracle中对数据行锁定时,行指向事务ID的一个副本,事务ID存储在包含数据的块中,释放锁时,事务ID却会保留下来。这个事务ID是事务所独有的,表示了撤销段号、槽和序列号。事务ID留在包含数据行的块上,可以告诉其他会话:你“拥有”这个数据(并非块上的所有数据都是你的,只是你修改的那一行“归你所有”)。另一个会话到来时,他会看到锁ID,由于锁ID表示一个事务,所以可以很快的查看持有这个锁的事务是否还是活动的。如果锁不活动,则允许会话访问这个数据。如果锁还是活动的,会话就会要求一旦释放锁就得到通知。因此,这就有了一个排队机制:请求锁的会话会排队,等待目前拥有锁的事务执行,然后的得到数据。
现在启动一个事务。
u1@ORCL> update dept set dname = initcap(dname);
已更新4行。
u1@ORCL> select username,
2 v$lock.sid,
3 trunc(id1 / power(2, 16)) rbs,
4 bitand(id1, to_number('ffff', 'xxxx')) + 0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER;
USERNAME SID RBS SLOT SEQ LMODE REQUEST
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
U1 25 6 4 9397 6 0
u1@ORCL> select XIDUSN, XIDSLOT, XIDSQN from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
6 4 9397
V$lock表中的LMODE为6是一个排他锁,REQUEST为0则意味着你没有发出请求。也就是说,你拥有这个锁。
0 - none1 - null (NULL)2 - row-S (SS) 行共享:共享表锁3 - row-X (SX) 行专用:用于行的修改4 - share (S) 共享锁:阻止其他DML操作5 - S/Row-X (SSX) 共享行专用:阻止其他事务操作6 - exclusive (X) 专用:独立访问使用
RBS、SLOT和SEQ值与v$transaction信息匹配。这就是我的事务ID。
下面使用同样的用户启动另一个会话,更新emp表中的某些行,并希望视图更新dept:
u1@ORCL> update emp set ename = upper(ename);
已更新14行。
u1@ORCL> update dept set deptno = deptno-10; --阻塞
现在这个会话会阻塞。如果再次运行V$查询,可以看到下面的结果:
u1@ORCL> select username,
2 v$lock.sid,
3 trunc(id1 / power(2, 16)) rbs,
4 bitand(id1, to_number('ffff', 'xxxx')) + 0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER;
USERNAME SID RBS SLOT SEQ LMODE REQUEST
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
U1 143 6 4 9397 0 6
U1 143 1 26 6920 6 0
U1 25 6 4 9397 6 0
u1@ORCL> select XIDUSN, XIDSLOT, XIDSQN from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
1 26 6920
6 4 9397
这里可以看到开始了一个新的事务,事务ID是(1,26,6920)。这一次这个新会话(SID=143)在V$LOCK中有两行。其中一行表示它所拥有的锁(LMODE=6)。另外还有一行,显示了一个值为6的REQUEST。这是一个对排他锁的请求。有意思的是,这个请求行的RBS/SLOT/SEQ值正是锁持有者的事务ID。SID=25的事务阻塞了SID=143的事务。只需要执行V$LOCK的一个自联结,就可以更明确的看出这一点:
u1@ORCL> select
2 (select username from v$session where sid=a.sid) blocker,
3 a.sid,
4 ' is blocking ',
5 (select username from v$session where sid=b.sid) blockee,
6 b.sid
7 from v$lock a, v$lock b
8 where a.block = 1
9 and b.request > 0
10 and a.id1 = b.id1
11 and a.id2 = b.id2;
BLOCKER SID 'ISBLOCKING' BLOCKEE SID
------------------------------ ---------- ------------- ------------------------------ ----------
U1 25 is blocking U1 143
另一个会话一旦放弃锁,请求行就会消失。这个请求行就是排队机制。如何用数据本身来管理锁定和事务信息。这是块开销的一部分。数据块的最前面有一个“开销”空间,这里会存放该块的一个事务表。对于锁定了该块中某些数据的各个“实际”事务,在这个事务表中都有一个相应的条目。这个结构的大小由创建对象时CREATE语句上的两个物理属性参数决定。
INITRANS:这个结构初始的预分配大小。对于索引和表,这个大小默认为2。
MAXTRANS:这个结构可以以扩展到的最大大小。它默认为255,实际中,最小值为2。在oracle 10g及更高的版本中,这个设置已经废弃了,所以不在使用。这个版本中的MAXTRANS总是255。默认情况下,每个块最开始都有两个事务槽。
2.2、TM锁
TM锁用于确保在修改表的内容时,表的结构不会改变。
u1@ORCL> insert into t1 values ( 1 );
已创建 1 行。
u1@ORCL> insert into t2 values ( 1 );
已创建 1 行。
u1@ORCL> select (select username
2 from v$session
3 where sid = v$lock.sid) username,
4 sid,
5 id1,
6 id2,
7 lmode,
8 request, block, v$lock.type
9 from v$lock
10 where sid = (select sid
11 from v$mystat
12 where rownum=1);
USERNAME SID ID1 ID2 LMODE REQUEST BLOCK TY
--------- ---------- ---------- ---------- ---------- ---------- ---------- --
U1 148 100 0 4 0 0 AE
U1 148 103209 0 3 0 0 TM
U1 148 103210 0 3 0 0 TM
U1 148 524301 10072 6 0 0 TX
u1@ORCL> select object_name, object_id
2 from user_objects
3 where object_name in ('T1','T2');
OBJECT_NAME OBJECT_ID
--------------- ----------
T1 103209
T2 103210
尽管每个事务只能得到一个TX锁,但是TM锁则不同,修改了多少个对象,就能得到多少个TM锁。在系统中允许的TM锁总数可以由你来配置(dml_locks参数定义)。实际上,这个数可能设置为0。但这并不是说你的数据库变成了一个只读数据库,而是说不允许DDL。通过使用ALTER TABLE TABLENAME DISABLE TABLE LOCK命令,还可以逐对象的禁用TM锁。这是一种快捷方法,可以使意外删除的表“难度更大”,因为在删除表之前,你必须重新启用表锁。
3、DDL锁
在DDL操作中会自动为对象加DDL锁,从而保护这些对象不会被其他会话所修改。例如,如果我执行一个DDL操作ALTER TABLE T,在表T上就会加一个排他DDL锁,以防止其他会话得到这个表的DDL锁和TM锁。
在oracle中DDL一定会提交。每条CREATE、ALTER等语句实际上都如下执行:
begin
commit;
DDL-STATEMENT
commit;
exception
when others then rollback;
end;
DDL一开始就提交,一定要知道这一点。
4、闩
闩(latch)是轻量级的串行化设备,用于协调对共享数据结构、对象和文件的多用户访问。
闩用于保护某些内存结构,如数据库块缓冲区或共享池中的库缓存。一般会在内部以一种“愿意等待”(willing to wait)模式请求闩。这说明,如果闩不可用,请求会话会睡眠很短的一段时间,并在以后再次尝试这个操作。还可以采用一种“立即”(immediate)模式请求其他闩,这与SELECT FOR UPDATE NOWAIT的思想很相似,说明这个进程会做其他事情(如获取另一个与之相当空闲闩),而不只是坐而等待这个闩直到它可用。由于许多请求者可能会同时等待一个闩,你会看到一些进程等待的时间比其他进程要长一些。闩的分配相当随机,这要看运气好坏了。闩释放后,紧接着不论哪个会话请求闩都会得到它。等待闩的会话不会排队,只是一大堆会话在不断的重试。
闩只保持很短的时间,而且提供了一种清理机制,万一某个闩持有者在持有闩时异常的“死掉了”,就能执行清理。这个清理过程有PMON执行。
队列锁(enqueue)这也是一种更复杂的串行化设备,例如,在更新数据库表中的行时就会使用队列锁。与闩的区别在于,队列锁允许请求者“排队”等待资源。对于闩请求,请求者会话会立即得到通知是否得到了闩。而对于队列锁,请求者会话会阻塞,直至真正得到锁。
4.1、闩“自旋”
等待闩可能是一个代价很高的操作。如果闩不是立即可用的,我们就得等待(大多数情况下都是如此),在一台多CPU机器上,我们的会话就会自旋(spin),也就是说,在循环中反复的尝试来得到闩。出现自旋的原因是,上下文切换(context switching)的开销很大(上下文切换是指被“踢出”CPU,然后又必须调度回CPU)。所以,如果进程不能立即得到闩,我们就会一直呆在CPU上,并立即再次尝试,而不是先睡眠、放弃CPU,等到必须调度回CPU时才再次尝试。之所以呆在CPU上,是因为我们指望闩的持有者正在另一个CPU上忙于处理(由于闩设计为只保持很短的时间,所以一般是这样),而且会很快放弃闩。如果出现自旋并不断的尝试想得到闩,但是之后还是得不到闩,此时我们的进程才回睡眠,或者让开CPU,而让其他工作进行。我们尝试得到闩时,可能会消耗大量的CPU时间。系统看上去非常忙(因为消耗了很多CPU时间),但是并没有做多少实际的工作。
- 9i10g11g编程艺术——锁和闩
- 9i10g11g编程艺术——事务
- 9i10g11g编程艺术——索引
- 9i10g11g编程艺术——数据类型
- 9i10g11g编程艺术——分区
- 9i10g11g编程艺术——redo与undo
- 9i10g11g编程艺术——过程并行化
- 9i10g11g编程艺术——并发与多版本控制
- 《程序员编程艺术:面试和算法心得》——目录
- 《程序员编程艺术:面试和算法心得》——目录
- 《程序员编程艺术:面试和算法心得》——目录
- Java并发编程的艺术(十三)——锁优化
- Java并发编程艺术——ReentrantReadWriteLock(读写锁)
- [读书笔记]javascript编程艺术——CH5 javascript编程原则和良好习惯
- Oracle 9i & 10g编程艺术-深入数据库体系结构——第6章:锁
- Unix编程艺术——微型语言
- Unix编程艺术——代码生成
- Unix编程艺术——配置
- 2003安全策略
- 高效代码审查的十个经验
- 面试100题系列之11在树中找到符合条件的路径
- FD快捷键
- cocos2d 横竖屏幕 适配ios6
- 9i10g11g编程艺术——锁和闩
- hdu 1867——A + B for you again(KMP)
- qemu-kvm部分流程/源代码分析
- Sidr – 创建侧栏和响应式菜单的最佳 jQuery 插件
- mac下图片批量处理
- [ZCJ][HTML]字体设置问题
- e2label , fstab, mkfs, partprobe, fdisk
- Cannot load /modules/libphp5.so into server: libXpm.so.4
- 策略模式(Strategy Pattern)(一):策略模式介绍