为了解决数据库被并发事物访问所带来的问题,数据库提供了锁机制来应对。数据库锁根据锁定的对象不同,可以分为表级锁和行级锁,表级锁锁定的对象是整张表,行级锁锁定的对象是特定的数据行;根据锁之间的关系可以分为共享锁和独占锁,共享锁允许其他事物获取共享锁,但是不予许其他事物获取独占锁。独占锁既不允许其他事物获取共享锁,又不允许其他事物获取独占锁。
行级锁:insert 、update、 delte 和 select…for update等都会隐士的获取一个行级锁。
表级锁:lock table tableName in shre mode 或 lock tabletableName in exclusive mode的获取一个表级锁。
共享锁:共享锁只支持表级锁,没有行级别的。通过lock table tableName in shre mode 添加。
独占锁:所有的行级锁都是独占锁。Lock table tableName inexlusive mode对整张表获取独占锁。
共享锁的行为:每个事物的共享锁都防止其他事物的独占锁,但是自己的共享锁不妨自己的独占锁。如果事物A独自获取了表T的共享锁,那么事物A还可以获取表T上的独占锁;如果事物A获取了表T的共享锁,事物B也获取了表T的共享锁,那么此时事物A不能获取T的独占锁了,因为事物B的共享锁不允许。
事物A:locktable tt_stu insharemode;
事物A进行如下操作会成功:insertinto tt_stu values(4,'a')
deletefrom tt_stu whereid=3;
update tt_stu setname='llll0l'whereid=1;
SELECT * FROM tt_stu whereid=2forupdate;
这四个操作都需要独占锁,因为只有自己持有共享锁,同一个事物的共享锁允许自己的独占锁。反过来自己的独占锁也不会排斥自己的共享锁,也就是自己不排斥自己。
如果上述情况,事物A在进行增删改查之前,事物B也执行了locktable tt_stu insharemode;则后四个操作会被阻塞,直到事物B提交了事物释放了共享锁。
如果上述情况,事物A执行了insert语句,则此时事物B去执行locktable tt_stu insharemode;事物B会被阻塞,因为事物A不仅有表上的共享锁,insert会隐式添加一个独占锁,阻止了事物B的共享锁。
独占锁的行为:每个事物的独占锁,都防止其他事物的共享锁和独占锁,允许自身事物的共享锁和独占锁。
事物A:locktable tt_stu inexclusivemode;
事物A进行如下操作都会成功:insertinto tt_stu values(4,'a');
deletefrom tt_stu whereid=2;
update tt_stu setname='llll0l'whereid=2 ;
SELECT * FROM tt_stu whereid=2forupdate;
locktable tt_stu insharemode;
因为他们在同一个事物,所以没影响。
行级独占锁和表级独占锁有区别:事物A执行:locktable tt_stu inexclusivemode;这是表独占锁,事物B无法获取该表的共享锁、及任意行的独占锁(也就是意味事物B无法进行增、删、改以及select…for update)。
如果事物A执行:SELECT * FROM tt_stu whereid=2forupdate;仅仅对id=2的数据行添加锁,事物B无法对id=2的数据行添加独占锁以及不能添加共享锁(因为共享锁只能是表级锁,包括id=2的行),但是事物B可以对其他数据行添加独占锁(可以对其他数据行进行修改删除以及执行insert)。
如果事物A执行:insertinto tt_stu values(4,'a');对id=4的数据行获取独占锁,事物B无法获取共享锁以及表独占锁(不可以执行locktable tt_stu insharemode和locktable tt_stu inexclusivemode),但是可以执行任意行独占锁(可以执行任意行insert、update、delte和select for update )。
PS: 普通的select语句无视锁的存在,锁对其没限制。
Oracle的5种表级锁:之前已经使用过了2种表级锁,表共享锁和表独占锁,以及行共享表级锁、行独占表级锁和表共享行独占表级锁。下图给出了表锁与表锁、dml、ddl的关系。
关系图(此处dml仅指增删改及select for update)
表共享:lock table tableNamein share mode;允许其他Session的表共享和行共享表级锁。阻止其他Session 的dml和select for update语句。
表独占:lock table tableNamein exclusive mode;阻止一切锁。阻止其他session的dml和 select for update语句。
行共享表级锁:select for update隐式添加,lock table tableName in row share mode;显式添加。仅允许其他Session获取行共享表级锁、行独占表级锁、表共享和表共享行独占表级锁。允许其他Session的DML和Select for update.
行独占表级锁:dml操作隐式添加,lock table tableName in row exclusivemode 显式添加。仅允许其他Session获取行共享表级锁和行独占表级锁。允许其他Session的DML和Select for update。
表共享行独占锁:lock table in sharerow exclusive mode;添加。仅允许其他Session获取行共享表级锁。阻止其他Session 的dml和select for update语句。
表共享和表独占2种表级锁与行级锁的互斥关系可以用共享锁独占锁分析,也可遵守上图与Dml语句的关系(因为dml除了select都会加行级锁,select for update也会),但是后面3种表级锁与行级锁的关系,只能遵守上图分析,不能直接根据共享锁和独占锁关系判断。
举例:
情况一:
A locktable tt_stu inrowexclusivemode;行共享表级锁
B locktable tt_stu insharerowexclusivemode;表共享行独站表级锁,AB不冲突。
情况二:
A SELECT * FROM tt_stu whereid=2forupdate;行共享表级锁(同情况一)
B locktable tt_stu insharerowexclusivemode;表共享行独站表级锁,AB产生冲突,因为表共享行独占锁会阻塞(ddl操作,和ddl互斥)。
要判断一个表级锁是否会阻塞另外一个表级锁,不仅要看表里的锁兼容性,还要判断是否dml隐式加锁从而判断是否支持dml,要这2个方面都支持才兼容。
PS:分析锁的关系时候,既要考虑表锁上的也要考虑行锁上的兼容性。5种表锁都不允许ddl操作。