锁概念基础数据库
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的状况。若对并发操做不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。安全
加锁是实现数据库并发控制的一个很是重要的技术。当事务在对某个数据对象进行操做前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了必定的控制,在该事务释放锁以前,其余的事务不能对此数据对象进行更新操做。session
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其余的事务不能对它读取和修改。加了共享锁的数据对象能够被其余事务读取,但不能修改。数据库利用这两 种基本的锁类型来对数据库的事务进行并发控制。并发
Oracle数据库的锁类型 oracle
根据保护的对象不一样,Oracle数据库锁能够分为如下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构。 app
DML锁的目的在于保证并发状况下的数据完整性,。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。 ide
当Oracle 执行DML语句时,系统自动在所要操做的表上申请TM类型的锁。当TM锁得到后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。 这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性便可,大大提升了系统的效率。TM锁包括了SS、SX、S、X 等多种模式,在数据库中用0-6来表示。不一样的SQL操做产生不一样类型的TM锁。 ui
在数据行上只有X锁(排他锁)。在 Oracle数据库中,当一个事务首次发起一个DML语句时就得到一个TX锁,该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行 DML语句时,第一个会话在该条记录上加锁,其余的会话处于等待状态。当第一个会话提交后,TX锁被释放,其余会话才能够加锁。 spa
当Oracle数据库发生TX锁等待时,若是不及时处理经常会引发Oracle数据库挂起,或致使死锁的发生,产生ORA-60的错误。这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。 .net
悲观封锁和乐观封锁1、悲观封锁
锁在用户修改以前就发挥做用:
Select ..for update(nowait)
Select * from tab1 for update
用户发出这条命令以后,oracle将会对返回集中的数据创建行级封锁,以防止其余用户的修改。
若是此时其余用户对上面返回结果集的数据进行dml或ddl操做都会返回一个错误信息或发生阻塞。
1:对返回结果集进行update或delete操做会发生阻塞。
2:对该表进行ddl操做将会报:Ora-00054:resource busy and acquire with nowait specified.
缘由分析
此时Oracle已经对返回的结果集上加了排它的行级锁,全部其余对这些数据进行的修改或删除操做都必须等待这个锁的释放,产生的外在现象就是其余的操做将发生阻塞,这个这个操做commit或rollback.
一样这个查询的事务将会对该表加表级锁,不容许对该表的任何ddl操做,不然将会报出ora-00054错误::resource busy and acquire with nowait specified.
阻塞
定义:
当一个会话保持另外一个会话正在请求的资源上的锁定时,就会发生阻塞。被阻塞的会话将一直挂起,直到持有锁的会话放弃锁定的资源为止。4个常见的dml语句会产生阻塞
INSERT
UPDATE
DELETE
SELECT…FOR UPDATE
INSERT
Insert发生阻塞的惟一状况就是用户拥有一个建有主键约束的表。当2个的会话同时试图向表中插入相同的数据时,其中的一个会话将被阻塞,直到另一个会话提交或会滚。一个会话提交时,另外一个会话将收到主键重复的错误。回滚时,被阻塞的会话将继续执行。
UPDATE 和DELETE当执行Update和delete操做的数据行已经被另外的会话锁定时,将会发生阻塞,直到另外一个会话提交或会滚。
Select …for update
当一个用户发出select..for update的错做准备对返回的结果集进行修改时,若是结果集已经被另外一个会话锁定,就是发生阻塞。须要等另外一个会话结束以后才可继续执行。能够经过发出 select… for update nowait的语句来避免发生阻塞,若是资源已经被另外一个会话锁定,则会返回如下错误:Ora-00054:resource busy and acquire with nowait specified.
死锁-deadlock
定义:当两个用户但愿持有对方的资源时就会发生死锁.
即两个用户互相等待对方释放资源时,oracle认定为产生了死锁,在这种状况下,将以牺牲一个用户做为代价,另外一个用户继续执行,牺牲的用户的事务将回滚.
例子:
1:用户1对A表进行Update,没有提交。
2:用户2对B表进行Update,没有提交。
此时双反不存在资源共享的问题。
3:若是用户2此时对A表做update,则会发生阻塞,须要等到用户一的事物结束。
4:若是此时用户1又对B表做update,则产生死锁。此时Oracle会选择其中一个用户进行会滚,使另外一个用户继续执行操做。
原由:
Oracle的死锁问题实际上不多见,若是发生,基本上都是不正确的程序设计形成的,通过调整后,基本上都会避免死锁的发生。
表1 Oracle的TM锁类型 | |||
锁模式 | 锁描述 | 解释 | SQL操做 |
0 | none | ||
1 | NULL | 空 | Select |
2 | SS(Row-S) | 行级共享锁,其余对象只能查询这些数据行 | Select for update、Lock for update、Lock row share |
3 | SX(Row-X) | 行级排它锁,在提交前不容许作DML操做 | Insert、Update、Delete、Lock row share |
4 | S(Share) | 共享锁 | Create index、Lock share |
5 | SSX(S/Row-X) | 共享行级排它锁 | Lock share row exclusive |
6 | X(Exclusive) | 排它锁 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
1. 关于 V$lock 表和相关视图的说明
Column |
Datatype |
Description |
ADDR |
RAW(4 | 8) |
Address of lock state object |
KADDR |
RAW(4 | 8) |
Address of lock |
SID |
NUMBER |
Identifier for session holding or acquiring the lock |
TYPE |
VARCHAR2(2) |
Type of user or system lock The locks on the user types are obtained by user applications. Any process that is blocking others is likely to be holding one of these locks. The user type locks are: TM - DML enqueue TX - Transaction enqueue UL - User supplied -- 咱们主要关注TX 和TM 两种类型的锁 --UL 锁用户本身定义的,通常不多会定义,基本不用关注 -- 其它均为系统锁,会很快自动释放,不用关注 |
ID1 |
NUMBER |
Lock identifier #1 (depends on type) |
ID2 |
NUMBER |
Lock identifier #2 (depends on type) --- 当lock type 为TM 时,id1 为DML-locked object 的object_id --- 当lock type 为TX 时,id1 为usn+slot ,而id2 为seq 。 -- 当lock type 为其它时,不用关注 |
LMODE |
NUMBER |
Lock mode in which the session holds the lock:
--大于0时表示 当前会话以某种模式 占有 该锁,等于0时表示当前会话正在等待该锁资源,即表示该会话被阻塞。 -- 每每在发生TX 锁时,伴随着TM 锁,好比一个sid=9 会话拥有一个TM 锁,通常会拥有一个或几个TX 锁,但他们的id1 和id2 是不一样的,请注意 |
REQUEST |
NUMBER |
Lock mode in which the process requests the lock:
-- 大于0时,表示当前会话被阻塞,其它会话占有改锁的模式 |
CTIME |
NUMBER |
Time since current mode was granted |
BLOCK |
NUMBER |
The lock is blocking another lock 0, 'Not Blocking', /* Not blocking any other processes */
|
2.其它相关视图说明
视图名 | 描述 | 主要字段说明 |
v$session | 查询会话的信息和锁的信息。 | sid,serial#:表示会话信息。 program:表示会话的应用程序信息。 row_wait_obj#:表示等待的对象,和dba_objects中的object_id相对应。 lockwait :该会话等待的锁的地址,与v$lock的kaddr对应. |
v$session_wait | 查询等待的会话信息。 | sid:表示持有锁的会话信息。 Seconds_in_wait:表示等待持续的时间信息 Event:表示会话等待的事件,锁等于enqueue |
dba_locks | 对v$lock的格式化视图。 | Session_id:和v$lock中的Sid对应。 Lock_type:和v$lock中的type对应。 Lock_ID1: 和v$lock中的ID1对应。 Mode_held,mode_requested:和v$lock中 的lmode,request相对应。 |
v$locked_object | 只包含DML的锁信息,包括回滚段和会话信息。 | Xidusn,xidslot,xidsqn:表示回滚段信息。和 v$transaction相关联。 Object_id:表示被锁对象标识。 Session_id:表示持有锁的会话信息。 Locked_mode:表示会话等待的锁模式的信 息,和v$lock中的lmode一致。 |
select a.sid holdsid,b.sid waitsid,a.type ,a.id1,a.id2,a.ctime from v$lock a,v$lock b
where a.id1=b.id1 and a.id2=b.id2 and a.block = 1 and b.block = 0 ;