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)
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/,如需转载,请注明出处,否则将追究法律责任。