oracle 锁

本文深入探讨了Oracle数据库的锁机制,包括DML锁中的TX和TM锁,以及DDL锁和内部的闩。特别强调了不使用绑定变量导致的CPU时间增加和自旋行为对系统资源的影响。此外,还介绍了手动锁定数据的方法,如SELECT...FOR UPDATE和DBMS_LOCK包的使用,以实现对数据和外部资源的串行访问控制。
摘要由CSDN通过智能技术生成
Oracle中主要有3类锁:

1. DML锁 数据操纵语言(Data Manipulation Language),SELECT、INSERT、UPDATE、MERGE和DELETE语句。

DML锁机制允许并发执行数据修改。例如,DML锁可能是特定数据行上的锁,或者是锁定表中所有行的表级锁。

2. DDL锁 数据定义语言(Data Definition Language),如CREATE和ALTER语句等。

DDL锁可以保护对象结构定义。

3. 内部锁和闩 保护Oracle内部数据结构。例如,Oracle解析一个查询并生成优化的查询计划时,它会把库缓存“临时闩”,将计划放在那里,以供其他会话使用。

闩(latch)是Oracle采用的一种轻量级的低级串行化设备,功能上类似于锁。闩是数据库中导致竞争的一个常见原因。

轻量级指的是闩的实现,而不是闩的作用。



DML锁

用于确保一次只有一个人能修改某一行,而且你正在处理一个表时别人不能删除这个表。

1. TX锁(事务锁)

事务发起第一个修改时会得到TX锁,而且会一直持有这个锁,直至事务执行提交(COMMIT)或回滚(ROLLBACK)。

TX锁用作一种排队机制,使得其他会话可以等待这个事务执行。事务中修改或通过SELECT FOR UPDATE选择的每一行都会“指向”该事务的一个相关TX锁。

在Oracle中,闩为数据的一个属性。Oracle并没有一个传统的锁管理器,不会为系统中锁定的每一行维护一个长长的列表。

如果数据库中有一个传统的基于内存的锁管理器,在这样一个数据库中,对一行锁定的过程一般如下:
(1) 找到想锁定的那一行的地址。
(2) 在锁管理器中排队(锁管理器必须是串行化的,因为这是一个常见的内存中的结构)。
(3) 锁定列表。
(4) 搜索列表,查看别人是否已经锁定了这一行。
(5) 在列表中创建一个新的条目,表明你已经锁定了这一行。
(6) 对列表解锁。
既然已经锁定了这一行,接下来就可以修改它了。之后,在你提交修改时,必须继续这个过程,如下:
(7) 再次排队。
(8) 锁住锁的列表。
(9) 在这个列表中搜索,并释放所有的锁。
(10) 对列表解锁。

Oracle中的锁定过程如下:
(1) 找到想锁定的那一行的地址。
(2) 到达那一行。
(3) 锁定这一行(如果这一行已经锁定,则等待锁住它的事务结束,除非使用了NOWAIT选项)。


事务只是找到数据,如果数据还没有被锁定,则对其锁定。

在Oracle中对数据行锁定时,行指向事务ID的一个副本,事务ID存储在包含数据的块中,释放锁时,事务ID却会保留下来。

这个事务ID是事务所独有的,表示了回滚段号、槽和序列号。

事务ID留在包含数据行的块上,可以告诉其他会话:“拥有”这个数据(并非块上的所有数据,只是修改的那一行)。

另一个会话到来时,它会看到锁ID,由于锁ID表示一个事务,所以可以很快地查看持有这个锁的事务是否还是活动的。

如果锁不活动,则允许会话访问这个数据。如果锁还是活动的,会话就会要求一旦释放锁就得到通知。

因此,这就有了一个排队机制: 请求锁的会话会排队,等待目前拥有锁的事务执行,然后得到数据

以下是一个小例子,展示了这到底是怎么回事,这里使用了3个V$ 表:
1. V$TRANSACTION,对应每个活动事务都包含一个条目。
2. V$SESSION,显示已经登录的会话。
3. V$LOCK,对应持有所有enqueue队列锁以及正在等待锁的会话,都分别包含一个条目。不存在行级锁的一个主列表。如果某个会话将EMP表中的一行锁定,V$LOCK视图中就有对应这个会话的一行来指示这一事实。如果一个会话锁定了EMP表中的数百万行,V$LOCK视图中对应这个会话还是只有一行。这个视图显示了各个会话有哪些队列锁。
scott@ORCL>create table dept_bak as select * from dept;
表已创建。

scott@ORCL>update dept_bak set deptno = deptno+10;
已更新4行。

下面来看看此时系统的状态:
scott@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
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
SCOTT                                  68          6          0       2146	6          0


scott@ORCL>select XIDUSN, XIDSLOT, XIDSQN
  2  from v$transaction;


    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
         6          0       2146
1. $LOCK表中的LMODE为6,REQUEST为0。 LMODE=6是一个排他锁请求(REQUEST)值为0则意味着没有发出请求;也就是说,你拥有这个锁
2. 这个表中只有一行。V$LOCK表更应算是一个队列表而不是一个锁表。Oracle不会在任何地方存储行级锁的列表(不会为每一个被锁定的行维护一个主列表)。要查看某一行是否被锁定,必须直接找到这一行。
3. 选择 ID1和ID2列,并对它们执行了一些处理。Oracle需要保存3个16位的数,但是对此只有两个列。所以,第一个列ID1保存着其中两个数。通过用trunc(id1/power (2,16))rbs除以2^16,并用bitand(id1,to_number('ffff','xxxx'))+0 slot把高位屏蔽,就能从这个数中找回隐藏的两个数。
4. RBS、SLOT和SEQ值与V$TRANSACTION信息匹配。这就是我的事务ID。


下面使用scott启动另一个会话,更新EMP_bak中的某些行,并希望试图更新DEPT_bak:
scott@ORCL>update emp_bak set ename = lower(ename);
已更新15行。

scott@ORCL>update dept_bak set deptno = deptno-10;

现在会话2会阻塞。如果会话1 再次运行V$查询,可以看到下面的结果:
scott@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
------------------------------ ---------- ---------- ---------- ----------	---------- ----------
SCOTT                                 133          6          0       2146	0          6
SCOTT                                  68          6          0       2146	6          0
SCOTT                                 133          8   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值