这个例子是说明:共享锁和更新锁可以同时在同一个资源上。这被称为共享锁和更新锁是兼容的。
例9:
----------------------------------------
T1:
begin
select * from table(updlock) (加更新锁)
update table set column1='hello' (重点:这里T1做update时,不需要等T2释放什么,而是直接把更新锁升级为排他锁,然后执行update)
T2:
begin
select * from table (T1加的更新锁不影响T2读取)
update table set column1='world' (T2的update需要等T1的update做完才能执行)
我们以这个例子来加深更新锁的理解,
第一种情况:T1先达,T2紧接到达;在这种情况中,T1先对表加更新锁,T2对表加共享锁,假设T2的select先执行完,准备执行update,
发现已有更新锁存在,T2等。T1执行这时才执行完select,准备执行update,更新锁升级为排他锁,然后执行update,执行完成,事务
结束,释放锁,T2才轮到执行update。
第二种情况:T2先达,T1紧接达;在这种情况,T2先对表加共享锁,T1达后,T1对表加更新锁,假设T2 select先结束,准备
update,发现已有更新锁,则等待,后面步骤就跟第一种情况一样了。
这个例子是说明:排他锁与更新锁是不兼容的,它们不能同时加在同一子资源上。
排他锁(独占锁,Exclusive Locks)
这个简单,即其它事务既不能读,又不能改排他锁锁定的资源。
例10
T1: update table set column1='hello' where id<1000
T2: update table set column1='world' where id>1000
假设T1先达,T2随后至,这个过程中T1会对id<1000的记录施加排他锁.但不会阻塞T2的update。
例11 (假设id都是自增长且连续的)
T1: update table set column1='hello' where id<1000
T2: update table set column1='world' where id>900
如同例10,T1先达,T2立刻也到,T1加的排他锁会阻塞T2的update.
意向锁(Intent Locks)
意向锁就是说在屋(比如代表一个表)门口设置一个标识,说明屋子里有人(比如代表某些记录)被锁住了。另一个人想知道屋子
里是否有人被锁,不用进屋子里一个一个的去查,直接看门口标识就行了。
当一个表中的某一行被加上排他锁后,该表就不能再被加表锁。数据库程序如何知道该表不能被加表锁?一种方式是逐条的判断该
表的每一条记录是否已经有排他锁,另一种方式是直接在表这一层级检查表本身是否有意向锁,不需要逐条判断。显然后者效率高。
例12:
----------------------------------------
T1: begin tran
select * from table (xlock) where id=10 --意思是对id=10这一行强加排他锁
T2: begin tran
select * from table (tablock) --意思是要加表级锁
假设T1先执行,T2后执行,T2执行时,欲加表锁,为判断是否可以加表锁,数据库系统要逐条判断table表每行记录是否已有排他锁,
如果发现其中一行已经有排他锁了,就不允许再加表锁了。只是这样逐条判断效率太低了。
实际上,数据库系统不是这样工作的。当T1的select执行时,系统对表table的id=10的这一行加了排他锁,还同时悄悄的对整个表
加了意向排他锁(IX),当T2执行表锁时,只需要看到这个表已经有意向排他锁存在,就直接等待,而不需要逐条检查资源了。
例13:
----------------------------------------
T1: begin tran
update table set column1='hello' where id=1
T2: begin tran
update table set column1='world' where id=1
这个例子和上面的例子实际效果相同,T1执行,系统对table同时对行家排他锁、对页加意向排他锁、对表加意向排他锁。
计划锁(Schema Locks)
例14:
----------------------------------------
alter table .... (加schema locks,称之为Schema modification (Sch-M) locks
DDL语句都会加Sch-M锁
该锁不允许任何其它session连接该表。连都连不了这个表了,当然更不用说想对该表执行什么sql语句了。
例15:
----------------------------------------
用jdbc向数据库发送了一条新的sql语句,数据库要先对之进行编译,在编译期间,也会加锁,称之为:Schema stability (Sch-S) locks
select * from tableA
编译这条语句过程中,其它session可以对表tableA做任何操作(update,delete,加排他锁等等),但不能做DDL(比如alter table)操作。
Bulk Update Locks 主要在批量导数据时用(比如用类似于oracle中的imp/exp的bcp命令)。不难理解,程序员往往也不需要关心,不赘述了。
3何时加锁?
如何加锁,何时加锁,加什么锁,你可以通过hint手工强行指定,但大多是数据库系统自动决定的。这就是为什么我们可以不懂锁也可
以高高兴兴的写SQL。
例15:
----------------------------------------
T1: begin tran
update table set column1='hello' where id=1
T2: SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED -- 事物隔离级别为允许脏读
go
select * from table where id=1
这里,T2的select可以查出结果。如果事物隔离级别不设为脏读,则T2会等T1事物执行完才能读出结果。
数据库如何自动加锁的?
1) T1执行,数据库自动加排他锁
2) T2执行,数据库发现事物隔离级别允许脏读,便不加共享锁。不加共享锁,则不会与已有的排他锁冲突,所以可以脏读。
例16:
----------------------------------------
T1: begin tran
update table set column1='hello' where id=1
T2: select * from table where id=1 --为指定隔离级别,则