数据库的锁
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。
在oracle数据库中有两种基本的锁类型
1.排它锁(Exclusive Locks,即X锁)
2.共享锁(Share Locks,即S锁)。
当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
锁定:通俗的讲就是加锁。锁定是Microsoft SQL Server数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制。
定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数据行、数据页或是整个数据表,当锁定运行时,会阻止其他事务对已经锁定的数据行、数据页或数据表进行操作。只有在当前事务对于自己锁定的资源不在需要时,才会释放其锁定的资源,供其他事务使用。
(一)共享锁
共享锁(S锁)允许并发事务在封闭式并发控制下读取(SELECT)资源。
当查询(SELECT)某条记录时,SQL SERVER会尝试取得该条记录的上存在共享锁(S锁),或无法获取,就必须等待别人释放对该记录中某几种与共享锁互斥的锁,才能在设置共享锁之后,获取该条记录。
举例来说:当某人查询某张表的一条记录时,就会在该记录上放置共享锁,在而其他人也要查询这张表的此记录时,因为共享锁彼此不互斥,所以也可以再次放置共享锁,也就是说SQL SERVER允许不同连接同时读取相同的数据。如果此时有人要更新此记录,因为独占锁与共享锁互斥,所以无法放置独占锁,要等到所有读取此记录的人都读取完毕,释放了共享锁,更新数据的人才能对该记录设置独占锁,并进一步更新数据。一般情况下,在默认的事务隔离级别下,当数据读取完毕,SQL SERVER就会释放共享锁,除非有特别的设置。
(二)更新锁
更新锁是一种中继锁。当同一项资源从原来的查询操作转换为更新操作时,锁定机制会从共享锁变为更新锁,再进一步变成独占锁。
在可重复读或可序列化事务中,此事务读取数据[获取资源(页或行)的共享锁(S锁)],然后修改数据[此操作要求锁转换为独占锁(X锁)]。 如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为独占锁(X锁)。 共享模式到独占锁的转换必须等待一段时间,因为一个事务的独占锁与其他事务的共享模式锁不兼容;发生锁等待。 第二个事务试图获取独占锁(X锁)以进行更新。 由于两个事务都要转换为独占锁(X锁),并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
若要避免这种潜在的死锁问题,请使用更新锁(U锁)。 一次只有一个事务可以获得资源的更新锁(U锁)。 如果事务修改资源,则更新锁(U锁)转换为独占锁(X锁)。
例如,当查询一条记录后,要将此内容更新(Update语句加上Where条件),一定会先查找记录,在查找的过程中就会对相关的记录放置共享锁,等找到相应的记录之后,SQL SERVER会先对记录放置更新锁,以避免发生死锁。因为共享锁与更新锁并不互斥,如果两个人同时对同一条记录放置共享锁,先进行更新的人,可以在别人也对同一条记录放置了共享锁时,继续放置更新锁,但因为更新锁互斥,所以当另一个人想再放置更新锁时,将无法设置,而进入停止等待状态。
(三)独占锁(也可称为排他锁)
独占锁(排他锁)(X锁)可以防止并发事务对资源进行访问。 使用独占锁(X锁)时,任何其他事务都无法修改数据;仅在使用NOLOCK提示或未提交读隔离级别时才会进行读取操作。
对数据进行添加、修改、删除操作时(如INSERT、UPDATE和DELETE), 语句在执行所需的操作之前首先执行读取操作以获取数据。 因此,需先对所在的资源放置独占锁,以确保以上操作未完成时,不受到干扰,独占锁在开启事务之后,一直保留到事务结束。例如,UPDATE语句可能根据与一个表的联接修改另一个表中的行。 在此情况下,除了请求更新行上的独占锁之外,UPDATE语句还将请求在联接表中读取的行上的共享锁。
(四)意向锁
在记录上放置共享锁之前,需要对存放该记录的更大范围(如数据页或数据表)上设置意向锁,以避免其他连接对该页放置独占锁。
数据库引擎使用意向锁来保护共享锁(S锁)或独占锁(X锁)放置在锁层次结构的底层资源上。 意向锁之所以命名为意向锁,是因为在较低级别锁前可获取它们,因此会通知意向将锁放置在较低级别上。
意向锁有两种用途:
· 防止其他事务以会使较低级别的锁无效的方式修改较高级别资源。
· 提高数据库引擎在较高的粒度级别检测锁冲突的效率。
例如:http://www.cnblogs.com/chillsrc/archive/2013/04/13/3018386.html
(五)架构锁
数据库引擎在表数据定义语言(DDL)操作(例如添加列或删除表)的过程中使用架构修改(Sch-M)锁。 保持该锁期间,Sch-M锁将阻止对表进行并发访问。 这意味着Sch-M锁在释放前将阻止所有外围操作。
某些数据操作语言(DML)操作(例如表截断)使用Sch-M锁阻止并发操作访问受影响的表。
数据库引擎在编译和执行查询时使用架构稳定性(Sch-S)锁。Sch-S锁不会阻止某些事务锁,其中包括排他(X)锁。 因此,在编译查询的过程中,其他事务(包括那些针对表使用X锁的事务)将继续运行。 但是,无法针对表执行获取Sch-M锁的并发DDL操作和并发DML操作。
(六)大容量更新锁
数据库引擎在将数据大容量复制到表中时,指定 TABLOCK 提示或使用 sp_tableoption 选项(将数据表设置为 table lock on bulk load),则是使用大容量更新锁(BU)。 大容量更新锁(BU锁)允许多个线程将数据并发地大容量加载到同一表,以降低数据表的锁定竞争,同时防止其他不进行大容量加载数据的进程访问该表。
(七)键范围锁
在使用可序列化事务隔离级别时,保护用户对于查询时所读取的数据行范围,以确保其他事务无法插入受“键范围锁”保护的数据行。键范围锁放置在索引上,指定开始与结束的索引键值。这些操作会先在索引上获取锁定,此种锁定可以封锁任何尝试进行插入、修改、删除索引键值在“键范围锁”中的数据行。例如:在索引键值“AAA”至“CZZ”范围中放置键范围锁,避免其他事务将含有索引键值的数据行插入到该范围内的任何地方,例如:“ABC”、“BCD”、“CEF”。另外当UPDATE语句搭配WHERE子句时,当SQL SERVER还在查找数据时,也有可能会设置键范围锁。