深刻理解数据库锁

本文以oracle数据库学习数据库锁

锁的分类

oracle中分为两种模式的锁,一种是排他锁(X锁),另外一种是共享所(S锁).数据库

  • 排他锁,也能够叫写锁
  • 共享所,也能够叫读锁

锁是实现并发的主要手段,在数据库中应用频繁,但不少都由数据库自动管理,当事务提交后会自动释放锁.编程

锁的类型

Oracle为了使数据库实现高度并发访问,它使用了不一样类型的锁来管理并发会话对数据对象的操做.Oracle的锁按做用对象不一样分为以下几种类型.
  • DML锁: 该类型的锁被称为数据锁,用于保护数据
  • DDL锁: 能够保护模式中对象的结构
  • 内部闩锁: 保护数据库的内部结构,彻底自动调用

这里主要介绍下经常使用的DML锁,它主要保证了并发访问时数据的完整性.它又能够分为如下两种类型的锁:
1) 行级锁(TX),也能够称为事务锁.当修改表中某行记录时,须要对将要修改的记录加行级锁,防止两个事务同时修改相同记录,事务结束,该锁也会释放,是粒度最细的锁.该锁只能属于排他锁(X锁).并发

2) 表级锁(TM),主要做用书防止在修改表的数据时,表的结构发生变化.例如,会话S在修改表A的数据时,它会获得表A的TM锁,而此时将不容许其余会话对该表进行变动或删除操做. 该状况的验证过程以下:oracle

UPDATE TABLE_NAME SET COLUMN= 'test' WHERE ID = 'id';

此时已经锁定该表,表级锁将不容许在事务结束前其余会话对表TABLE_NAME进行DDL操做.
其次,在执行DROP TABLE TABLE_NAME操做,执行后会提示ORA-00054错误.
缘由是:
在执行DML操做时,数据库会先申请数据对象上的共享锁,防止其余会话对该对象执行DDL操做。一旦申请成功,则会对将要修改的记录申请排他锁,若是此时其余会话正在修改该记录,那么等待其事务结束后再为修改的记录加上排他锁。性能

表级锁包含以下集中模式:

  • ROW SHARE:行级共享锁(RS)。该模式下不容许其余的并行会话对同一张表使用排他锁,但容许其利用DML语句或lock命令锁定同一张表中的其余记录。SELECT...FROM FOR UPDATE 语句就是给记录加上了RS锁.
  • ROW EXCLUSEIVE, 行级排他锁(RX).该模式下容许并行会话对同一张表的其余数据进行修改,但不容许并行会话对同一张表使用排他锁.
  • SHARE,共享锁(S).该模式下,不容许会话更新表,但容许会话对表添加RS锁.
  • SHARE ROW EXCLUSIVE,共享行级排他锁(SRX).该模式下,不能对同一张表进行DML操做,也不能添加S锁.
  • EXCLUSIVE,排他锁(X).该模式下,其余的并行会话不能对表进行DML和DDL操做,该表只能读.

下表列出了以上5中模式相互之间的兼容关系.其中,✔表示相互兼容,×表示相互不兼容学习

\ RS S RX SRX X
RS ×
S × × ×
RX × ×
SRX × × × ×
X × × × × ×

下面所示是Oracle中的各类SQL语句所产生的表级锁模式以及容许的锁定模式状况的汇总.code

SQL语句 表锁模式 RS S RX SRX X
SELECT ...FROM table NONE Y Y Y Y Y
INSERT INTO ... RX Y N Y N N
UPDATE table ... RX Y N Y N N
DELETE FROM table ... RX Y N Y N N
SELECT * FROM table FOR UPDATE RX Y N Y N N
LOCK TABLE table IN ROW SHARE MODE RS Y Y Y Y N
LOCK TABLE table IN ROW EXCLUSIVE MODE RX Y N Y N N
LOCK TABLE table IN SHARE MODE S Y N N N N
LOCK TABLE table IN SHARE ROW EXCLUSIVE MODE SRX Y N N N N
LOCK TABLE table IN EXCLUSIVE MODE X N N N N N

在Oracle中除了执行DML时自动为表添加TM锁外,也能够主动地为表添加TM锁,语法以下:对象

LOCK TABLE [schema.] table IN 
[EXCLUSIVE] 
[SHARE]
[ROW EXCLUSIVE]
[SHARE ROW EXCLUSIVE]
[ROW SHARE* | SHARE UPDATE*]
MODE [NOWAIT]

DDL锁也能够称为数据字典锁,主要做用是保护模式中对象的结构.当执行DDL操做时首先Oracle会自动地隐式提交一次事务,而后自动地给处理对象加上锁;当DDL结束时,Oracle会隐式地提交事务并释放DDL锁.与DML不一样的是,用户不能显式的要求使用DDL锁.事务

DDL锁分为以下3类:资源

  • Exclusive DDL Lock,排他DDL锁定.若是对象加上了该类型的锁,那么对象不能被其余会话修改,并且该对象也不能再增长其余类型的DDL锁.若是是表,此时能够读取数据.
  • Shared DDL Lock,共享DDL锁定.保护对象的结构,其余会话不能修改该对象的结构,可是容许修改数据.
  • Breakable Parsed Lock,能打破的解析锁定.该类型的锁能够被打断,不能禁止DDL操做.

锁等待与死锁

锁等待

在某些状况下因为占用的资源不能及时释放,而形成锁等待,也能够叫锁冲突.锁等待会严重地影响数据库性能和平常工做.

例如当一个会话修改表A的记录时,它会对该记录加锁,而此时若是另外一个会话也来修改此记录,那么第二个会话将因得不到排他锁而一直等待,此时会出现执行SQL时数据库长时间没有响应的现象.直到第一个会话把事务提交,释放锁,第二个会话才能对数据进行操做.

下面为你们示例锁等待现象:

  1. 打开SLQ*PLUS窗口,修改PRODUCTINFO 表中PRODUCTID 字段为1的记录,脚本以下:

UPDATE PRODUCTINFO SET ORIGIN = '修改1' WHERE PRODUCTID = 1;

此时虽然提示已更新,但事务并无提交.接下来进行第二步操做.

  1. 打开另外一个SQL*PLUS 窗口,一样修改PRODUCTINFO 表中PRODUCTID字段为1的记录,脚本以下:

UPDATE PRODUCTINFO SET ORIGIN = '修改2' WHERE PRODUCTID = 1;

此时执行效果不会提示已更新,而是一直等待.

此时的状况是由于第一个会话封锁了该记录,但事务没有结束,锁不会释放,而这时第二个会话也要修改同一条记录,但它缺没有办法得到排他锁,因此只能等待.若是第一个会话修改数据的事务结束,那么第二个会话会结束等待.及时地结束事务是解决锁等待状况发生的有效方法.

死锁

死锁的发生和锁等待不一样,它是锁等待的一个特例,一般发生在两个或者多个会话之间.假设一个会话想要修改两个资源对象,能够是表也能够是字段,修改这两个资源的操做在一个事务当中,当它修改第一个对象时须要对其锁定,而后等待第二个对象,这时若是另一个会话也须要修改这两个资源对象,而且已经得到对第二个对象的锁定,那么就会出现死锁,由于当前会话锁定了第一个对象等待第二个对象,而另外一个会话锁定了第二个对象等待第一个对象.这样,两个会话都不能获得想要获得的对象,因而出现死锁.

这里例子就不在展现,你们能够自行试一试.实际开发中出现死锁状况大体有如下几种缘由:

  1. 用户没有良好的编程习惯,偶尔会忘记提交事务,致使长时间占用资源.
  2. 操做的记录过多,并且操做过程当中没有良好地对其分组.对于数据两很大的操做,能够将其分红几组提交事务,这样能够避免长时间的占用资源.
  3. 逻辑错误,两个会话都想获得已占有的资源.
相关文章
相关标签/搜索