1 概述
1.1 加锁的目的:实现对 ‘共享资源’ 的 ‘并发控制’
例如,‘同时’ 更新 ‘同一条记录’
若不加锁,则更新无先后顺序,得到的结果集可能并非想要的
若加了锁,则更新有先后顺序,能得到想要的结果集
1.2 锁的分类:从不同的角度,有不同的分类方法
1.3 相关视图
select * from v$locked_object; – 查询 dml 锁信息
select * from dba_ddl_locks; – 查询 ddl 锁信息
(3) select * from v$lock; – 查询所有锁信息
2 锁的类型
2.1 按用户与系统划分:隐式锁和显式锁
隐式锁(自动锁): Oracle 系统自行维护,无需人为干预,常见有
(1) DDL 语句:create、alter 等
(2) DML 语句:insert、update、delete、select … for update
显式锁: 人为手动添加锁,lock table … [nowait]
(1) lock table <table_name> in row share mode nowait; – 2:rs
(2) lock table <table_name> in share update mode nowait; – 2:rs
(3) lock table <table_name> in row exclusive mode nowait; – 3:rx
(4) lock table <table_name> in share mode nowait; – 4:s
(5) lock table <table_name> in share row exclusive mode; – 5:srx
(6) lock table <table_name> in exclusive mode nowait; – 6:x
2.2 按锁的机制划分: 共享锁和排他锁
共享锁( S ): 如果事务T对表A加上共享锁,则事务T可以读该表,但是不能修改该表数据。其他事务也只能对该对象加上共享锁,但是不能加上排他锁。这就保证了其他事务可以读A表数据,但是不能修改A表数据(这就不会影响到读该表的事务了,有利于并发操作)。
排他锁( X ): 如果事务T对对象A加上排他锁,则只允许T对A对象读取和修改,其他事务不能对A增加任何锁,直到T释放加在A上的排他锁。
基本锁类型 | 简称 | 能否再加锁 | 能否读数据 | 能否改数据 |
---|---|---|---|---|
共享锁 | Share Locks,即 S 锁 | √ | √ | × |
排他锁 | Exclusive Locks,即 X 锁 | × | √ | √ |
2.3 按保护对象划分:DML Locks、DDL Locks、SYSTEM Locks
DML Locks: 保护 ‘数据’,如:表锁锁定整个表、行锁锁定选中的行
(1) Row Locks (TX) 称为行级锁或事务锁。当事务执行 DML 语句(INSERT, UPDATE, DELETE, and SELECT with the FOR UPDATE clause)时会申请TX 类型的锁,TX 的机制是排他锁。
(2) Table Locks (TM ) 称为表级锁。当Oracle执行 DML 语句时,系统自动在所要操作的表上申请TM类型的锁。
TM锁类型表细分:
RS: row share
RX: row exclusive
S: share
SRX: share row exclusive
X: exclusive
注:Y的含义是完全不阻塞其它事务对相应锁的申请;Y*的含义是不阻塞其它事务对相应锁的申请(同表不同行),但对同一行数据申请相应的琐时则会发生等待;N的含义是阻塞其它事务对相应锁的申请。
DDL Locks: 保护 ‘对象的结构’,如:表、视图的定义
排他DDL锁(Exclusive DDL lock):阻塞其他会话得到该对象的DDL锁或DML锁。在DDL操作期间你可以查询一个表,但是无法以任何方式修改这个表。
共享DDL锁(Share DDL lock):保护所引用对象的结构,使其结构不会被其他会话修改。
System locks: 保护数据库 ‘内部的结构’,如:数据文件、闩
“锁模式” 值越大,所影响的行数越多!
详细解释可参考 Oracle 官方文档 v$locked_object 中的 locked mode 链接(Oracle Database Concepts …)
锁模式 | 简称 | 全称 | 解释 | 常用 sql 操作 |
---|---|---|---|---|
0 | none | lock requested but not yet obtained | 已请求锁,但未获得 | |
1 | null | 查询 | select | |
2 | rows_s(ss) | row share lock | 行级共享锁 | |
3 | row_x(sx) | row exclusive table lock | 行排它表锁 | insert、update、delete |
4 | share(s) | share table lock | 共享表锁 | |
5 | s/row-s(ssx) | share row exclusive table lock | 共享行独占表锁 | |
6 | exclusive(x) | exclusive table lock | 排它表锁 | alter table、drop table、drop index、truncate table |
lock table 的方式,同上 “2.1 按用户与系统划分:隐式锁和显式锁”
比较少用,故不在此赘叙
小结:
在上表中的TM锁又分为7个级别,其中,R代表行,S代表共享,如下表所示:
3 锁的兼容性
常见SQL语句的锁兼容情况如下表所示:
4 扩展
4.1 select … for update 进阶
文章 | 简述 |
---|---|
Oracle for update skip locked 详解 | 跳过被锁定的记录,锁定未被锁定的记录 |
Oracle for update [of column] [nowait] 详解 | 多表连接时,锁定单个表中的某列 |
4.2 死锁
死锁原因:互相等待对象释放资源。 – 我让你先走,你让我先走,结果大家都不走
解决办法:找到 ‘SID’ 和 ‘SERIAL#’,并执行下列语句
alter system kill session 'SID, SERIAL#';
’SID’ 和 ‘SERIAL#’ 获取方式:
SELECT l.sid "会话ID",
s.serial# "会话序列号",
p.spid "会话进程号",
l.type "锁类型",
s.username "所属用户",
s.machine "客户端",
o.object_name "被锁对象",
o.object_type "被锁对象类型",
l.ctime "被锁时间(S)"
FROM v$lock l, -- addr
v$session s, -- saddr
dba_objects o, -- object_id
v$process p -- addr
WHERE s.sid = l.sid
AND o.object_id = l.id1
AND p.addr = s.paddr
AND l.type IN ('TM', 'TX') -- 只需要关注 TM / TX 锁即可
-- AND s.username = ''
;
参考:
https://blog.csdn.net/qq_34745941/article/details/106939087
https://www.cnblogs.com/polestar/p/3325732.html
https://mp.weixin.qq.com/s?src=11×tamp=1675409123&ver=4327&signature=gSH4D0dqcAa2mtch2PSUaz71XGslwjTSCWBK45bMbTp2AjFZdKowVGyI3Odi7UENIeIH2eoxxkMg0cHMQctp0bzLFn2KIYltyNawXWE0OpCplFg2OEKvVTEy-ecYZb&new=1
相关文章: