所以只要想要并发的修改表中相同的行,在第一个获取锁的事务没有结束前,后面的时候都会发生阻塞。
_dexter@FAKE>select * from tun2_tab ;
ID NAME
--------------------------------------------------
1 dexter
2 dexter
3 NN
session1 session_id=144 :
_dexter@FAKE>delete from tun2_tab where id =1 ;
1 rowdeleted.
session2 session_id=18 :
_dexter@FAKE>delete tun2_tab where id >1 ;
2 rowsdeleted.
session3 session_id=9 :
_dexter@FAKE>delete tun2_tab ;
waiting...
_sys@FAKE>/
SID TYPE ID1 LMODE REQUEST BLOCK
-------------- ---------- ---------- ---------- ----------
9 TX 524317 0 6 0
9 TM 82618 3 0 0
18 TX 655383 6 0 0
18 TM 82618 3 0 0
144 TX 524317 6 0 1
144 TM 82618 3 0 0
6 rowsselected.
发生了阻塞,只有当session 1 和session 2 的事务结束后,session 3 才可以顺利完成。
|
|
Session1 |
Session2 |
Session3 |
Description |
| T1 |
delete from tun2_tab where id =1 ; |
|
|
|
| T2 |
|
delete tun2_tab where id >1 ; |
|
session2 delete 操作因为不包括session 1 中的id=1的记录,所以可以顺利执行 |
| T3 |
|
|
delete tun2_tab ; waiting … |
session3 delete操做,因为需要获取id=1,id>1记录的事务锁,所以发生了等待。可以看到它首先是在等待id=1的事务锁。 |
下面有两个有趣的实验
有趣小实验1
_dexter@FAKE>select * from tun2_tab ;
ID NAME
--------------------------------------------------
1 dexter
2 dexter
3 NN
session1 session_id=22:
_dexter@FAKE>delete from tun2_tab where id =2 ;
1 rowdeleted.
session2 session_id=18:
_dexter@FAKE>update tun2_tab set name ='dexter' where id>1 ;
waiting...
session3 session_id=9:
_dexter@FAKE>delete tun2_tab where id = 3 ;
1 rowdeleted.
查看一下锁的情况:
_sys@FAKE>/
SID TYPE ID1 LMODE REQUEST BLOCK
-------------- ---------- ---------- ---------- ----------
9 TX 393228 6 0 0
9 TM 82618 3 0 0
18 TX 131089 0 6 0
18 TM 82618 3 0 0
22 TX 131089 6 0 1
22 TM 82618 3 0 0
6 rowsselected.
这里比较有趣了,因为session 2 update 的记录包括id=2这一行,所以在id=2这一行加锁的时候,这里发生了transaction enqueue,它还没来得及对任何记录加锁,就已经进入了等待中。
而session3执行的时候发现id=3 的这一行还没有锁标示,所以它顺利的对id=3 的记录加了锁。
这个时候我们rollback 第一条记录后
session1 :
_dexter@FAKE>rollback ;
Rollbackcomplete.
发现session2 依然处于等待状态中
再看一下锁的情况:
_sys@FAKE>/
SID TYPE ID1 LMODE REQUEST BLOCK
-------------- ---------- ---------- ---------- ----------
9 TX 393228 6 0 1
9 TM 82618 3 0 0
18 TX 589840 6 0 0
18 TX 393228 0 6 0
18 TM 82618 3 0 0
这个时候我们可以看到session2又在等待session3的事务结束以便获取id=3这条记录的锁。
|
|
Session1 |
Session2 |
Session3 |
Description |
| T1 |
delete from tun2_tab where id =2 ; |
|
|
|
| T2 |
|
update tun2_tab set name ='dexter' where id>1 ; waiting… |
|
session 2 因为要获取id=2的记录的事务锁所以发生阻塞,等待session1 中的事务释放。 |
| T3 |
|
|
delete tun2_tab where id = 3 ; |
按照正常人的思维,比如说我。这一句应该等待session2中的事务才对。但是事实不是如此。因为session2陷入了阻塞,没还没有对id=3的记录加上事务锁,所以session3可以顺利执行。 |
| T4 |
commit; |
|
|
|
| T5 |
|
still waiting |
|
因为需要id=3的记录的事务锁,所以又被阻塞。 |
有趣小实验2
session1session_id=144:
_dexter@FAKE>delete from tun2_tab where id =3 ;
1 rowdeleted.
session2session_id=18:
_dexter@FAKE> update tun2_tab set name ='dexter' whereid>1 ;
waiting..
session3session_id=9:
_dexter@FAKE>delete tun2_tab where id = 2 ;
waiting..
看一下锁情况:
SID TYPE ID1 LMODE REQUEST BLOCK
-------------- ---------- ---------- ---------- ----------
9 TX 196635 0 6 0
9 TM 82618 3 0 0
18 TX 196635 6 0 1
18 TM 82618 3 0 0
18 TX 458767 0 6 0
144 TM 82618 3 0 0
144 TX 458767 6 0 1
7 rowsselected.
session 3 也进入了等待中,因为session2 先获取了id=2 的行锁,然后等待id=3 的行锁。
|
|
Session1 |
Session2 |
Session3 |
Description |
| T1 |
delete from tun2_tab where id =3 ; |
|
|
|
| T2 |
|
update tun2_tab set name ='dexter' where id>1 ; |
|
session 2 因为要获取id=3的记录的事务锁所以发生阻塞,但是在阻塞之前,以及对id=1|2的 |