通过实验来理解行级锁的发生
1.创建需要的表
SQL> conn / as sysdba
已连接。
SQL> create table dept as select * from scott.dept;
表已创建。
SQL> create table emp as select * from scott.emp;
表已创建。
SQL> alter table dept add constraint dept_pk primary key(deptno);
表已更改。
SQL> alter table emp add constraint emp_pk primary key(empno);
表已更改。
SQL> alter table emp add constraint emp_fk_dept foreign key(deptno) references dept(deptno);
表已更改。
SQL> create index emp_deptno_idx on emp(deptno);
索引已创建。
2.执行更新操作
SQL> update dept set dname=initcap(dname);
已更新4行。
3.查看此时的系统状态
SQL> set linesize 200 pagesize 1000
SQL> 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
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
SYS 68 3 23 898 6 0
通过列表可以看出lmode=6是排它锁,request=0代表没有锁请求,就是说更新了表的数据没有另一个会话更新同一条数据,就没有锁请求
SQL> select XIDUSN,XIDSLOT,XIDSQN from v$transaction;查出来的信息是事务ID可以和查询出的锁信息相对应。
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
3 23 898
4.在一个新的会话中登录相同的用户,执行更新操作
SQL> update emp set ename=upper(ename);
已更新14行。
SQL> update dept set deptno=deptno-10;
5.查看系统信息
SQL> 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
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
SYS 130 3 23 898 0 6
SYS 68 3 23 898 6 0
SYS 130 5 33 872 6 0
SQL> select XIDUSN,XIDSLOT,XIDSQN from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
3 23 898---第一次
5 33 872---第二次
在事务信息中多了一条,在锁的信息中多了两条,其中一条请求为排他锁6,他的rbs/slot/seq与第一次的相同,说明给他加锁的就是第一次的更新操作,他在请求这个锁,来获得资源,在第二个会话中第一条语句由于也没有提交所以他也出现了排它锁。
通过锁的自联结就可以更清楚的看出他们之间谁锁了谁
SQL> 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
------------------------------ ---------- ----------- ------------------------------ ----------
SYS 68 is blocking SYS 130
6.提交事务,查询锁信息
SQL> commit;
提交完成。
SQL> 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
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
SYS 130 5 33 872 6 0
SQL> select XIDUSN,XIDSLOT,XIDSQN from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
5 33 872
SID为68的锁不见了,130的锁只剩下了一个,有锁请求的信息也消失了,这就解释了oracle的锁机制,首先oracle的行锁不会使用锁队列管理,在第二个会话中有两个更新操作没有提交,如果是队列管理应该会有两个锁信息,现在只有一个,那在第一个会话没有提交的时侯出现两个锁信息,是因为第一个会话更新的时候对行加了排它锁,第二个会话想更新相同的行,就要向会话一发出锁请求,所以在锁信息里才有它的出现,但是它的出现,他的模式是0这样就可以理解了。
相关 脚本总结
查询锁得相关信息
查询当前会话的操作的锁状态
select username,
v$lock.sid,
trunc(id1/power(2,16)) rbs,
bitand(id1,to_number('ffff','xxxx'))+0 slot,
id2 seq,
lmode,
request
from v$lock,v$session
where v$lock.type='TX'
and v$lock.sid=v$session.sid
and v$session.username=USER;
在事务视图中找到相应的对照信息
select XIDUSN,XIDSLOT,XIDSQN from v$transaction;
查看锁的自联结信息,可以查看谁把谁锁定了
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
'is blocking',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a,v$lock b
where a.block=1
and b.request >0
and a.id1=b.id1
and a.id2=b.id2;