该系列的博客都是基于《数据库系统概论》第五版王珊一书
前提:
因为最近要升学的原因,再加上重温数据库部分内容,所以整理一份比较详细且重点的笔记。适合有考研升学需求的人收藏
**
B站里也是有该老师的上课视频:链接放在下面:
https://www.bilibili.com/video/BV1pW411W7Do?from=search&seid=17230259822734539218
(不过年代比较久远,而且画质一般,有兴趣的可以听听)
第十一章 并发控制
//了解
数据库并发控制技术的必要性
活锁与死锁的概念
掌握
:
1. 并发操作可能产生数据不一致的情况,包括丢失修改、不可重复读、读“脏”数据等
2. 封锁的类型及不同封锁类型(X锁、S锁)的性质和定义,相关的相容控制矩阵
3. 封锁协议的概念
4. 封锁粒度的概念,多粒度封锁方法,多粒度封锁协议的相容控制矩阵
5. 封锁协议与数据一致性的关系,并发调度的可串行性概念
6. 两段锁协议与可串行性的关系,两段锁协议与死锁的关系
tips:什么是并发呢?简单理解就是同时很多人吃同一碗饭。
为什么要并发控制?能保证事务哪些特性?
数据库是共享资源,通常有许多个事务同时在运行。
当多个事务并发地存取数据库时就会产生同时读取和/或修改同一数据的情况
。若对并发操作不加控制就可能会存取和存储不正确的数据,破坏数据库的一致性。
并发控制可以保证事务的【一致性】和【隔离性】
并发操作可能会产生哪几类数据不一致?用什么方法能避免
- **丢失修改(LostUpdate)**两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了(覆盖了)T1提交的结果,导致T1的修改被丢失。
- **不可重复读(Non-RepeatableRead)**不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。
-
读“脏”数据(DirtyRead)
读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。
避免的方法:并发控制(封锁技术,时间戳方法,乐观控制方法,多版本并发控制方法等)
封锁技术?类型有?
封锁就是事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其他的事务不能更新此数据对象。
基本的封锁类型有两种:
排它锁(简称X锁)
和
共享锁(简称S锁)
。(如何快速记住:x 就是xie的拼音,而S就是share分享的英文。所以就是x就是写锁也是排他锁,s就是共享锁)
排它锁又称为写锁
。若事务T对数据对象A加上X锁,则只允许T读取和修改A,
其他任何事务都不能再对A加任何类型的锁
(
排他的含义
),直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。
共享锁又称为读锁
。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,
其他事务只能再对A加S锁,而不能加X锁
,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
总结一句话:加s锁只能读但还可以加s锁,加了x锁可以读和修改但不可以再加任何锁
如何用封锁机制保证数据的一致性
**DBMS在对数据进行读写操作之前首先对该数据执行封锁操作**
活锁?产生原因和解决方法?
概念的详细可以参考该书,我用简单一话解释一下:
活锁: 活锁就是某个事务在在等待资源时不断有人插队。
(相当于你排队买奶茶,不断有人插队)
原因:当一系列封锁不能按照其先后顺序执行时,就可能导致一些事务无限期等待某个封锁,从而导致活锁
方法:采用先来先服务的策略。当多个事务请求封锁同一数据对象时,封锁子系统按请求封锁的先后次序对事务排队,数据对象上的锁一旦释放就批准申请队列中第一个事务获得锁。
死锁?产生的原因和解决方法?
死锁:就是两个以上的事务分别请求封锁对方已经封锁的数据,导致长期等待而无法继续运行下去的现象。
(相当于你在一个已经关了门的奶茶店门前买奶茶,永远等都是没有用的,因为已经关门了)
原因:是两个或多个事务都已封锁了一些数据对象,然后又都请求已被其他事务封锁的数据加锁,从而出现死等待。
方法
:
一次封锁法
(要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行。)
顺序封锁法
(预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁。)
如何检测发生了死锁?
超时法
(如果一个事务的等待时间超过了规定的时限,就认为发生了死锁。)
事务等待法图法
DBMS并发控制子系统检测到死锁后,就要设法解除。通常采用的方法是选择一个处理死锁代价最小的事务,将其撤消,释放此事务持有的所有锁,使其他事务得以继续运行下去。
(一句话就是,会牺牲最小代价的那个事务)
可串行化的调度?
可串行化的调度是正确的调度,定义:多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同,我们称这种调度策略为可串行化的调度
。
为什么要引进意向锁? 意向锁的含义是什么?
引进意向锁是为了提高封锁子系统的效率。
原因
:在多粒度封锁方法中,一个数据对象可能以两种方式加锁—显式封锁和隐式封锁。因此系统在对某一数据对象加锁时不仅要检查该数据对象上有无(显式和隐式)封锁与之冲突;还要检查其所有上级结点和所有下级结点,看申请的封锁是否与这些结点上的(显式和隐式)封锁冲突;显然,这样的检查方法效率很低。为此引进了意向锁。
含义
:对任一结点加锁时,必须先对它的上层结点加意向锁。引进意向锁后,系统对某一数据对象加锁时不必逐个检查与下一级结点的封锁冲突了。
一句话是:奶茶就是事务,而对奶茶的操作就是加锁,先检查奶茶是否开过(检查其所有上级结点和所有下级结点),然后再将奶茶是否加冰后传个下一个人(再加锁)
常用的意向锁
IS锁:如果对一个数据对象加IS锁,表示它的后裔结点拟(意向)加S锁。例如,要对某个元组加S锁,则要首先对关系和数据库加IS锁
一句话:拿到奶茶后加冰块(或者其他东西)给下个人喝,所以下个人喝的是冰奶茶
IX锁:如果对一个数据对象加IX锁,表示它的后裔结点拟(意向)加X锁。例如,要对某个元组加X锁,则要首先对关系和数据库加IX锁。
SIX锁:如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX = S + IX
。
一句话:也就是先加冰(s)再封口(x),但是没有先封口再加冰,因为
x锁(排它锁)加了以后不可以加任何锁了,所以也就没有XIS锁,只有SIX锁
两段锁协议
两段锁协议是指所有事务必须分两个阶段对数据项
加锁
和
解锁
。
在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁;
在释放一个封锁之后,事务不再申请和获得任何其他封锁。
“两段”的含义是,事务分为两个阶段:
第一阶段是获得封锁
,也称为扩展阶段。在这阶段,事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁。**
第二阶段是释放封锁
,也称为收缩阶段。在这阶段,事务释放已经获得的锁,但是不能再申请任何锁
图引自自己的另一篇博客:
更清晰去全方位理解数据库
课后答案
- 为了防止一个用户的工作不适当地影响另一个用户,应该采取【并发控制】
- 解决并发操作带来的数据不一致问题普遍采用【封锁】技术。
- 下列不属于并发操作带来的问题是【死锁】
- DBMS普遍采用【封锁】方法来保证调度的正确性
- 事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放,这是【一级封锁协议】
- 如果事务T获得了数据项Q上的排他锁,则T对Q【既可读又可写】
- 设事务T1和T2,对数据库中地数据A进行操作,可能有如下几种情况
- 请问哪一种不会发生冲突操作【T1正在读A,T2也要读A】
- 如果有两个事务,同时对数据库中同一数据进行操作,不会引起冲突的操作是【两个都是SELECT】
- 在数据库系统中,死锁属于【事务故障】