ITPub博客

首页 > Linux操作系统 > Linux操作系统 > oracle 数据库的锁

oracle 数据库的锁

原创 Linux操作系统 作者:pingley 时间:2012-04-13 22:17:36 0 删除 编辑
oracle 数据库的锁
oracle 数据库中的锁可以分为三类,TX,TM和user defined locks(UL).这里只介绍TX和TM。
Row Locks(TX)
     行级锁也叫做TX 锁。该种锁放置在一个表中的行级上。当在进行insert,updatedetele,merge 或者select ... for update 的时候事务会请求锁住相应的行。当显式或者隐式发出commit,rollback 的时候才会解除事务锁定的行。行级锁其实是一种队列机制,用来防止两个事务同时修改相同的行。oracle 数据库总是互斥的锁住需要修改的行,直到事务终结(commit 或者rollback)。行级锁是粒度最小的锁,所以能够提高数据库系统的并发性和吞吐量。
如果事务请求锁定表中的某些行,事务也需要在该表上加一个锁。这个表级锁的目的是防止冲突的DDL 操作,DDL操作将会影响到表的结构,从而影响当前正在对该表进行操作的事务。行级锁TX和表级锁TM同属于oracle DML锁,都是由oracle主动根据事务的需要添加的。行级锁的信息是存储在oracle 数据库 block header中的。通常在表级有两种锁模式:X 锁也就是所谓的互斥锁。 S 锁也就是所谓的共享锁。但是在oracle 中在表级有7 种锁模式,null和没有锁也算是锁模式。所以oracle
数据库为了保证在并发情况数据的一致性和完整性所实施的锁机制是比较复杂的。
X 锁:用于互斥的访问资源。同时阻止其他会话在相同的资源上放置S 锁或者 X锁。
S 锁:用户共享的访问资源。可以允许多个会话在同一个资源上面放置多个S 锁,但是不允许任何会话在加有S 锁的资源上面放置 X 锁。
因此当我们需要对数据进行修改的时候我们需要一个X 锁,当我们需要对读取数据同时并且保证没有人在并发的修改数据我们需要一个S 锁。在这种只有S和X锁的情况下当一个会话修改了数据我们必须等到事务提交或者回滚以后才能查询,这是可以选择等待或者撤销读操作。而oracle 对锁的实现则灵活很多。
oracle 数据库中表级锁的模式如下:
1、Row Exclusive Table Lock (RX)也称作subexclusive table lock (SX),rows-X.该锁的含义是在(sub)行级放置一个X锁。
通常表明持有这种锁的事务是已经更新了表中的相应记录或者是由于select ... for update引起的。SX 锁允许其他事务进行查询,插入,更新,删除,或者并发的锁住表中的记录。因此SX锁允许多个事务同时在相同的表上获得SX 和SS 锁。注:这里的允许是由条件的,不能是已经被RX的行。
SQL> select sid from V$mystat where rownum = 1;  
       SID
----------
         1
#该会话标记为session1.
SQL> select sid,type,id1,id2,lmode
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE
---------- -- ---------- ---------- ----------
         1 AE        100          0          4
使用select ... for update 语句根据where 子句锁定相应的行。
SQL> select * from hr.employees
  2  where employee_id < 105
  3  for update;
SQL> select sid,type,id1,id2,lmode
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE
---------- -- ---------- ---------- ----------
         1 AE        100          0          4
         1 TM      67516          0       3
         1 TX     589849       1083    6
可见在发出select ...for update 语句以后oracle 在 表employees 上放置了一个TM为RX的锁。表示的含义是select ...for update 中的记录加了一个X锁。在另外一个会话中(session2)我们发出相同的select ... for update 语句。同时在session1 中查询v$lock。
SQL> select sid from V$mystat where rownum = 1;
       SID
----------
        39
#该会话标记为session2.
SQL> select * from hr.employees
  2  where employee_id < 105
  3  for update;
^Cselect * from hr.employees
                 *
ERROR at line 1:
ORA-01013: user requested cancel of current operation
该操作会被阻塞,所以一直等待,我这里把它cancel 了。
在session2 中发出select ...for update 的时候,session 2 中的查询。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
        39 AE        100          0          4          0          0
        39 TX     589849       1083          0          6          0
        39 TM      67516          0          3          0          0
         1 TM      67516          0          3          0          0
         1 TX     589849       1083          6          0          1
6 rows selected.
我们可以从查询中看到session2 请求一个行级的互斥锁(X)。并且session 1阻塞了一个会话,这个会话就是 session2,因为session2 请求的行级的X锁已经被sesion2 持有了,所以session2 不得不等待。
注:不带for update 的select语句是在执行的时候oracle 不会添加任何的锁。
2、Row Share (RS),也称作subshare table lock(SS),row-S.该锁的含义是在(sub)行级上放置一个S锁。在oracle 9i以前 select ...for update 语句使用的就是这种锁,这种锁也可以达到查询数据的时候不允许并发的修改。
3、update,insert,delete 在表级放置的也都是RX 锁,也就是lock mode 等于3的那种锁。这个查询的目的是说明初始化环境。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
        39 AE        100          0          4          0          0
上面的执行的select ... for update 语句我已经rollback了。
夏天到了公司给员工加高温补贴。不提交。
SQL> update employees
  2  set salary = salary + 200
  3  where employee_id = 100;
1 row updated.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      67516          0          3          0          0
         1 TX     524298       1353          6          0          0
把上面的操作回滚掉。创建employees 的副本,用来执行detele 和 insert 操作。
SQL> create table emp as select * from employees;
Table created.
查看一下初始化环境。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
现在假如employee_id =145 的员工辞职不干了,hr要把他的资料信息从emp表中删除。不提交。
SQL> delete from emp
  2  where employee_id = 145;
1 row deleted.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      69469          0          3          0          0
         1 TX     196625       1146          6          0          0
可见detele 操作在在表级加的也是RX锁,因为要互斥使用资源,所有需要加X锁。现在假如来了一个新员工,hr要往emp 表中插入必要的信息。不提交。
SQL> insert into emp(employee_id,last_name,email,hire_date,job_id)
  2  values(321,'zhangfei','12345678@qq.com',sysdate,'IT_sup');
1 row created.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      69469          0          3          0          0
         1 TX     327692       1161          6          0          0
查询的结果和没有执行detele 操作的时候是相同的,这可以证明一下两点:oracle 实施饿锁机制是灵活的,你写你的我写我的,虽然是同一张表,但是只要是不同的列,是不会相互冲突或者干扰的。因为X锁放在了行级。这样有利于提高数据系统的并发性。
把上面两个事务都回滚掉。再次确认初始化环境。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
4、Share TableLock(S)。
持有这种锁的事务允许其他事务对表进行查询(不允许select...for update 方式)。只有当一个事务持有S 锁的时候才允许更新。因为多个事务可能并发的持有S 锁。持有这种锁不足以保证事务能够修改表中的记录。我们显式的发出对emp 表的一个S 锁定操作。
SQL> lock table emp in share mode;
Table(s) Locked.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      69469          0          4          0          0
由查询可以知道我们知道oracle在表emp 上放置了一个lock mode 为4 的锁,也就是share tablelock 锁。其他会话就不能对该表添加任何X 锁了。在session 2 中发出下面delete 操作。
SQL> delete from emp;
该操作会被阻塞在,那边一直等待。在session1 中进行查询会话相关的锁信息。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100           0             4            0            0
        39 AE        100          0             4            0            0
        39 TM      69469       0             0            3            0
         1 TM      69469        0             4            0            1
我们可以知道session 2 想在表上加一个lmode=3 的RX 锁。但是因为session 1已经把整个表都share lock 了,所以这种互斥锁添加不了。下面我撤销session 2
中的delete 操作。在继续试验。
SQL> delete from emp;
^Cdelete from emp
            *
ERROR at line 1:
ORA-01013: user requested cancel of current operation
在session 2 中往emp 在家一把S 锁是OK的。
SQL> lock table emp in share mode;
Table(s) Locked.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
        39 AE        100         0          4          0          0
        39 TM      69469      0          4          0          0
         1 TM      69469       0          4          0          0
在session 1 中发出如下的update 语句。
SQL> update emp
  2  set salary = salary + 200
  3  where employee_id = 100;
会一直阻塞在那边,因为在emp 上有两个S锁。在session 2中进行如下的查询。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
        39 AE        100         0          4          0          0
        39 TM      69469      0          4          0          1
         1 TM      69469       0          4          5          1
我们可以知道 session 1 在请求一个 lmode 为 5 的锁,但是被该会话自身和session 2 所阻塞。现在释放掉session 锁持有的S 锁。我们可以查看到session 1 中的update 语句执行成功。
SQL> update emp
  2  set salary = salary + 200
  3  where employee_id = 100;
1 row updated.
我们把上述的操作都回滚掉并验证下初始化环境,继续我们是实验。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
        39 AE        100          0          4          0          0
5、Exclusive Table Lock (X)。
这种锁是限制性最严格的,不允许其他事务执行任何类型的DML操作或者在表上放置任何类型的锁。当然单纯的select 语句还是允许的因为select 语句不需要任何的锁。可以显式的给一张表加一个S 锁,也可以显式的给一张表加一个X 锁。
SQL> lock table emp in exclusive mode;
Table(s) Locked.
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      69469       0          6          0          0
刚才我们执行的lock table 语句的结果就是在emp 表中放置了一个lmode =6 的锁,即X 锁。虽然emp 被加上了X 锁但是 单纯的select 查询还是可以的。
SQL> select last_name from emp
  2  where employee_id = 100;
LAST_NAME
-------------------------
test
注:这个test 是我以前对employees 所做的一个更新,所以成了现在我们看到的这个样子。
接下来在session 2 中执行DML 操作。来看看会发生什么情况。
SQL> delete from emp
  2  where employee_id = 145;
在session 2 中执行的这条 delete 操作会一直阻塞在那边,因为整张表已经被上了X 锁。下面在session 1 中进行如下的查询。
SQL> select sid,type,id1,id2,lmode,request,block
  2  from V$lock
  3  where sid = 1;
where sid in (1,39);
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
         1 AE        100          0          4          0          0
         1 TM      69469       0          6          0          1
session 2 会话的信息没有出现在查询结果中,但是我们可以看到session 1 阻塞了一个会话,这个会话就是session 2.我现在回滚掉sesion 1 中的lock table 操作,释放session 1所持有的 X 锁。我们可以看到session 2 中的那条原本正在等待的delete 信息马上返回执行成功。
SQL> delete from emp
  2  where employee_id = 145;
1 row deleted.
6、Share Row Exclusive Table Lock (SRX)。
这种锁,也叫做share-subexclusive table lock (SSX)。是限制性比S 锁更严格的一种锁。在一张表中一次只能允许一个事务持有SSX 锁。持有SSX 锁的事务允许别的事务进行查询该表(不允许select...for update 方式)。并且持有该锁的会话不更新该表。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26110315/viewspace-721120/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2012-02-06

  • 博文量
    169
  • 访问量
    741338