Oracle的锁有很多种类型,除了用户访问常用到的DDL,DML操作引起的锁以外,其实还有其他类型的锁,比如增加表空间(未做深入研究,再如新增extents,做truncation操作,还有临时表空间操作等)等操作。
总的来说,数据库上的锁有两种:
1 排它锁 exclusive locks 即X锁。加上排它锁,其他事务不能读取和修改。
2 共享锁 shared locks 即S锁。加上共享锁,其他事务可以读取但是不能修改。
下面涉及到的其他锁都是以这两种为基础从不同维度衍生出来的。
Oracle锁的五个类别:(很多文章的介绍中只列出前三或者前二)
1 DDL 锁,dictionary lock。字典锁。
2 DML 锁,data lock。数据锁。包括了TM和TX锁。
3 内部锁与闩,Oracle自己管理保护内部数据,通常用户不用关心(或许就类似于上面说到的extents增删,truncation操作等)。
4 Distributed locks 分布式锁,用于OPS(并行服务器中)。
5 PCM locks 并行告诉缓存锁,用于OPS(并行服务器中)。
Oracle锁的三个粒度,这是另一个维度。
1 TX 行级锁,即事务锁,设计到DML操作和commit/rollback操作。
2 TM 锁,表级锁,共五种。
3 数据库级锁,锁定数据库为限制模式alter system enable restricted session,还有startup mount、alter database open read only。这些与DBA密切相关,与一般用户关系不大。
悲观锁和乐观锁:
1 悲观锁:Select ..for update(nowait) 和 Select * from tab1 for update 操作,这种会在表的行上加排它锁,这样其他事务无法读取和修改。
2 乐观锁:数据在select后到update进行并提交的时间段中数据不会修改。这其实有潜在风险,就是select和update中间有其他事务修改了数据。
Oracle建议采用悲观锁,这样更安全。
TM锁类型:(网上查到的资料与我实践的结果不同,这里做了修正)
锁模式 | 锁描述 | 解释 | SQL操作 |
0 | none | ||
1 | NULL | 空 | Select |
2 | RS(Row-S) | 行级共享锁,其他对象只能查询这些数据行 | Lock for update 有这种操作?、Lock row share |
3 | RX(Row-X) | 行级排它锁,在提交前不允许做DML操作 | Insert、Update、Delete、Select for update、lock row exclusive |
4 | S(Share) | 共享锁 | Create index、Lock share |
5 | SRX(S/Row-X) | 共享行级排它锁 | Lock share row exclusive |
6 | X(Exclusive) | 排它锁 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
对于以上锁,从2到6都是有加锁操作的,下面是具体的例子:
模式 | 锁定的SQL | 排斥的模式 | 允许的DML |
2 RS | lock table t in row share mode; | 6 | select,insert,update,delete,for update |
3 RX | lock table t in row exclusive mode; select, insert, update, delete, for update(我加的) |
4,5,6 | select,insert,update, delete,for update |
4 S | lock table t in share mode; | 3,5,6 | select |
5 SRX | lock table t in share row exclusive mode; | 3,4,5,6 | select |
6 X | lock table t in exclusive mode; | 2,3,4,5,6 | select |
这其中,模式3可以很好理解,也常见,就是用户插入更新和删除数据时,对表加RX锁,这意味着表上的共享和行上的排它锁,这很容易理解。但是其他模式代表什么意思?不是完全明白。
从另一张图来描述:×表示排斥
- | N/A | RS | RX | S | SRX | X |
N/A | ||||||
RS | × | |||||
RX | × | × | × | |||
S | × | × | × | |||
SRX | × | × | × | × | ||
X | × | × | × | × | × |
SQL语句 | 表锁定模式 | 允许的表锁定模式 |
select * from ... |
RS |
RS RX S SRX S |
insert into ... | RX | RS RX |
update ... | RX | RS RX |
delete from ... | RX | RS RX |
select * from for update | RS??? RX??? | RS RX S SRX ??? RS RX??? |
lock table in row share mode | RS | RS RX S SRX |
lock table in row exclusive mode | RX | RS RX |
lock table in share mode | S | RS S |
lock table in share row exclusive mode | SRX | RS |
lock table in exclusive mode | X | RS |
这里有个疑问是关于select ... for update的操作,网上的资料显示TM都是RS操作,但是经过我的测试,都是RX操作。是因为数据库版本的问题么?这点不太清楚。
在Oracle中可以通过几个视图来查看锁状态。
v$lock dba_locks v$session v$session_wait v$locked_object
视图名 | 描述 | 说明 |
v$session | 查询会话的信息和锁的信息。 | sid,serial#:表示会话信息。 program:表示会话的应用程序信息。 row_wait_obj#:表示等待的对象,和dba_objects中的object_id相对应。 |
v$session_wait | 查询等待的会话信息。 | sid:表示持有锁的会话信息。 Seconds_in_wait:表示等待持续的时间信息 Event:表示会话等待的事件。 |
v$lock | 列出系统中的所有的锁。 | Sid:表示持有锁的会话信息。 Type:表示锁的类型。值包括TM和TX等。 ID1:表示锁的对象标识。 lmode,request:表示会话等待的锁模式的信息。用数字0-6表示,和表1相对应。 |
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_objects | 只包含DML的锁信息,包括回滚段和会话信息。 | Xidusn,xidslot,xidsqn:表示回滚段信息。和v$transaction相关联。 Object_id:表示被锁对象标识。 Session_id:表示持有锁的会话信息。 Locked_mode:表示会话等待的锁模式的信息,和v$lock中的lmode一致。 |
这里解释一下v$lock的代表:
列名 | 类型 | 字段说明 |
ADDR | RAW(4|8) | Address of lock state object |
KADDR | RAW(4|8) | Address of lock |
SID | NUMBER | 会话的sid,可以和v$session 关联 |
TYPE | VARCHAR2(2) | 锁保护对象的类型见上面 TM – DML enqueue TX – Transaction enqueue UL – User supplied 更多时候只需要关注TX和TM两种类型的锁 UL锁用户自己定义的,一般很少会定义,很少关注 其它均为系统锁,会很快自动释放,不用关注 |
ID1 | NUMBER | ID1,ID2的取值含义根据type的取值而有所不同 对于TM 锁 ID1表示被锁定表的object_id 可以和dba_objects视图关联取得具体表信息,ID2 值为0 对于TX 锁 ID1以十进制数值表示该事务所占用的回滚段号和事务槽slot number号,其组形式: 0xRRRRSSSS,RRRR=RBS/UNDO NUMBER,SSSS=SLOT NUMBER |
ID2 | NUMBER | ID2 以十进制数值表示环绕wrap的次数,即事务槽被重用的次数 |
LMODE | NUMBER | 0、无 1、NULL,可以某些情况下,如分布式数据库的查询会产生此锁。 2、SS,表结构共享锁 3、SX,表结构共享锁+被操作的记录的排它锁 4、S, 表结构共享锁+所有记录共享锁 5、SRX 表结构共享锁+所有记录排它锁 6、X 表结构排它锁+所有记录排它锁 以下为补充上面 摘自:http://www.itpub.net/thread-940126-1-1.html 2 SS, 表结构共享+加上部分数据共享.虽然有人说,ORACLE里,数据没有S状态,但我还是愿意这样理解: 第1个S代表表结构共享. 第2个代表表里的数据共享. 你可以想象一下,当往子表里增加纪录时,主表的相关主键是不是得处于共享模式. 3 SX, 用于DML操作,第1个S代表表结构共享,第2个代表表里被操作的数据独占. 4 S, 代表表结构+表里的数据都是处于共享模式.当对表创建索引时,在创建期间,表处于这种模式. 5 SRX=S(4)+SX(3), 6 X, 删除表是会用上. |
REQUEST |
NUMBER | 同上LMODE 大于0时,表示当前会话被阻塞,其它会话占有改锁的模式 |
CTIME | NUMBER | 已持有或者等待锁的时间 |
BLOCK | NUMBER | 是否阻塞其他会话锁申请 2:Global 1:阻塞 0:不阻塞 |
下面是具体详细的说明:
ADDR
Address of lock state object
KADDR
Address of lock
Lock Type
System Type
BL Buffer hash table instance
CF Control file schema global enqueue
CI Cross-instance function invocation instance
CU Cursor bind
DF Data file instance
DL Direct loader parallel index create
DM Mount/startup db primary/secondary instance
DR Distributed recovery process
DX Distributed transaction entry
FS File set
HW Space management operations on a specific segment
IN Instance number
IR Instance recovery serialization global enqueue
IS Instance state
IV Library cache invalidation instance
JQ Job queue
KK Thread kick
LA .. LP Library cache lock instance lock (A..P = namespace)
MM Mount definition global enqueue
MR Media recovery
NA..NZ Library cache pin instance (A..Z = namespace)
PF Password File
PI, PS Parallel operation
PR Process startup
QA..QZ Row cache instance (A..Z = cache)
RT Redo thread global enqueue
SC System change number instance
SM SMON
SN Sequence number instance
SQ Sequence number enqueue
SS Sort segment
ST Space transaction enqueue
SV Sequence number value
TA Generic enqueue
TS Temporary segment enqueue (ID2=0)
TS New block allocation enqueue (ID2=1)
TT Temporary table enqueue
UN User name
US Undo segment DDL
WL Being-written redo log instance
User Type
TX --- Transaction
TM --- Table Manipulate
UL --- PL/SQL USER LOCK
lmode(Lock mode)
Lock mode in which the session holds the lock:
- none
- null (NULL)
- row-S (SS)
- row-X (SX)
- share (S)
- S/Row-X (SSX)
- exclusive (X)
request
Lock mode in which the process requests the lock:
- none
- null (NULL)
- row-S (SS)
- row-X (SX)
- share (S)
- S/Row-X (SSX)
- exclusive (X)
Block
--- Not blocking any other processes
--- This lock blocks other processes
--- Global
在数据库中验证:
执行lock table <table name> in row share mode,然后在v$lock中可以看到有一条记录TM锁,LMODE值为2。同时有条TX记录,LMODE为6。这里的LMODE就代表了TM锁模式,RS RX S 等等。
block字段代表了是否有其他事务等待这个锁。
下面是查询锁的一些有用的SQL:
select * from v$session where sid in ( select sid from v$lock where block=1 or request=6);
select sid,serial#,sql_id,prev_sql_id,ROW_WAIT_OBJ#,ROW_WAIT_FILE#,ROW_WAIT_BLOCK#,ROW_WAIT_ROW# from v$session where sid in ( select sid from v$lock where block=1 or request=6);
select s.sid,s.SERIAL#,s.STATUS,s.MACHINE,s.username,s.OSUSER,s.BLOCKING_SESSION,s.SQL_ID,s.PREV_SQL_ID,s.BLOCKING_INSTANCE,s.BLOCKING_SESSION_STATUS
from v$session s
where s.BLOCKING_SESSION>0;
select s.sid,s.SERIAL#,s.STATUS,s.MACHINE,s.username,s.OSUSER,s.BLOCKING_SESSION,s.SQL_ID,s.PREV_SQL_ID,s.LOGON_TIME,s.BLOCKING_INSTANCE,s.BLOCKING_SESSION_STATUS
from v$session s where sid in ( select sid from v$lock where block=1 or request=6);
select s.sid,s.SERIAL#,s.STATUS,s.MACHINE,s.username,s.OSUSER,s.BLOCKING_SESSION,s.SQL_ID,s.PREV_SQL_ID,s.LOGON_TIME,s.BLOCKING_INSTANCE,s.BLOCKING_SESSION_STATUS
from v$session s
where s.BLOCKING_SESSION>0;
select sid,sql_id,prev_sql_id,
'select object_name from dba_objects where object_id='||ROW_WAIT_OBJ#||';',
'select dbms_rowid.rowid_create(1,'||ROW_WAIT_OBJ#||','||ROW_WAIT_FILE#||','||ROW_WAIT_BLOCK#||','||ROW_WAIT_ROW# ||') from dual;'
from v$session where sid in ( select sid from v$lock where block=1 or request=6)
order by sql_id;
死锁:
死锁是两个会话互相请求对方已锁定资源引起互相等待,oracle中会自动杀掉其中一个会话(什么样的选择机制?)。