保证一个数据同一时间只被一个失误操作 --> 最终保证事物的隔离性
并发场景中,很多连接连接到数据库进行进行操作,不同连接中的事物操作不同的数据
test 表 sal列
会话A
updata test set sal=300 where sal=100
-->buffer cache中数据块的数据是300
-->事物未提交
会话B
updata test set sal=sal*3 where sal=100
为了避免发生数据修改歧义,导致数据不一致,提出锁的机制保证事物隔离性
直到会话A中的事物结束(commit/rollback),则锁释放,资源可以被会话B修改
对于会话B而言,出现的状态叫锁等待,但实际上,我们从数据库角度来看
--> oracle数据块会维持一个队列
队列保证客户端发送请求的资源先到先得
会话A 持有资源
会话B 等待资源
会话C 等待资源
B和C虽然都在等待资源,但一旦资源释放,则优先B使用
队列中越靠后的请求,从客户端来讲,锁等待时间越长
锁粒度:锁对什么对象添加
在数据表上添加锁 --> 表锁
在数据页/数据块上添加所 --> 页锁/块锁
在数据行上添加锁 --> 行锁
Oracle/MySQL这种数据库,我们一般只谈表锁和行锁
客户端在执行操作时,无需关心锁机制
客户端的操作,不用先对数据加锁,然后在操作,然后在释放锁
加锁和释放锁的过程是自动的,客户端仅需要关注自己本身的操作即可
基于语句分析,自动添加粒度最小的锁 --> 行锁
锁升级概念:
Oracle和MySQL都没有锁升级机制
锁升级就是只当处理的数据量较大时,发生锁粒度的改变
行锁 升级 表锁
SQLServer中存在锁升级概念
Oracle中:
DML(数据操纵语言)操作会触发锁机制
DQL(数据查询语言)操作不会触发锁机制
select * from test --> 不触发锁
select * from test for update; --> 手动加锁
自动队列管理:
并发场景中会有不同的事务请求操作相同的数据
此时发生锁冲突,表现在客户端就是锁等待
Oracle内部维持队列,管理锁冲突请求,FIFO
事务处理结束前会一致保持锁定
rollback/commit 标记着事务结束,同时自动释放锁
网络异常导致连接断开,pmon检测到会话异常,回滚数据,自动释放锁
锁是数据库的异常吗?
锁是数据库中保证数据安全的基本机制,作为DBA无需处理锁等待事件。
锁等待是业务逻辑问题,和数据库性能好坏无关
Oracle中的锁
行锁
共享锁
排它锁
表锁
意向共享锁
意向排它锁
update test set sal=300 where id =100
要对test表进行加锁
意向排它锁,先对表进行临时锁定,锁定后,添加基于行的排它锁,释放意向锁
锁类型转换
同一会话中:
select * from test where id =100 --> 不加锁
select * from test where id =100 for update --> 添加share锁(S锁,共享锁)
锁转换 --> S 变成 X
update set sal =300 where id =100 -->添加exclusive锁(X锁 排它锁)
commit/rollback --> 锁自动释放
此时提交,意味着释放锁
队列中的其他会话可以按顺序获取该数据的锁
S锁:共享锁 对数据不能修改,但是可以查看
X锁:排它锁 对数据不能修改,也不能查看
S锁具有兼容性,可以兼容其他S锁
S锁和X锁不兼容
死锁:事务互相锁等待
数据 1000 数据 2000
会话A update 1000 --> 对1000加锁
会话B update 2000 --> 对2000加锁
会话A update 2000 --> 锁等待
会话B update 1000 --> 锁等待
会话A 和 会话B中的事务互相锁等待 --> 死锁
Oracle会自动检测死锁,将先执行的语句kill 掉
SQL> select OBJECT_ID,OBJECT_NAME from test where rownum<5;
OBJECT_ID OBJECT_NAME
---------- ------------------------------
20 ICOL$
46 I_USER1
28 CON$
15 UNDO$
会话A
SQL> update test set OBJECT_NAME='AAA' where OBJECT_ID=20;
1 row updated. --> ICOL$修改为AAA 修改未提交 锁定数据
会话B
SQL> update test set OBJECT_NAME='BBB' where OBJECT_ID=46;
1 row updated. --> I_USER1修改为BBB 修改未提交 锁定数据
会话A
SQL> update test set OBJECT_NAME='CCC' where OBJECT_ID=46;
--> 进入锁等待
--> 会话B锁定OBJECT_ID=46的数据,会话A无法获取锁,发生锁冲突,出现锁等待,等待会话B释放锁
会话B
SQL> update test set OBJECT_NAME='DDD' where OBJECT_ID=20;
--> 进入锁等待
--> 会话A锁定OBJECT_ID=20的数据,会话B无法获取锁,发生锁冲突,出现锁等待,等待会话A释放锁
Oracle会自动检测到这种状态 --> 死锁,将先执行的语句kill,报错如下
会话A
update test set OBJECT_NAME='CCC' where OBJECT_ID=46
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
会话B
SQL处于等待
会话B中操作OBJECT_ID=20数据的SQL等待会话A中事务结束
会话A
commit或rollback
这里执行rollback
会话B
执行成功
1 row updated.
这里执行 commit
SQL> select OBJECT_ID,OBJECT_NAME from test where rownum<5;
OBJECT_ID OBJECT_NAME
---------- ------------------------------
20 DDD
46 BBB
28 CON$
15 UNDO$
死锁问题是在高并发场景中,业务逻辑设计不当导致的数据块异常
DBA无法解决数据块死锁问题,需要从业务修改SQL




