文章目录
- 一、为什么要并发控制
- 1.2 并发控制解决的问题
- 1.2.1 脏读
- 1.2.2 幻读
- 1.2.3 不可重复读
- 1.2.4 数据丢失问题
- 二、事务调度及可串行性
- 2.1 事务
- 2.1.1 事务的宏观
- 2.1.2 事务的微观
- 2.1.3 事务的特性 ACID
- 2.2 事务调度与可串行性
- 2.3 冲突可串行化判定
- 三、基于封锁的并发控制方法
- 3.1 锁的类型
- 3.1.1 共享锁Shared Lock
- 3.1.2 排它锁Exclusive Lock
- 3.1.3 意向共享锁 Intent Shared Lock
- 3.1.4 意向排他锁 Intent Exclusive Lock
- 3.1.5 更新锁Update Lock
- 3.1.6 增量锁Incremental Lock
- 3.1.7 行级锁Row Lock
- 3.1.8 表级锁Row Lock
- 3.1.9 锁的优先级
- 3.2 加锁解锁时机
- 3.3 SQL隔离级别
- 3.3.1 读未提交 read uncommitted 0
- 3.3.2 读已提交 read committed 1
- 3.3.3 可重复读 repeatable read 2
- 3.3.4 可串行化 serializable 3
- 3.4 两段锁协议
- 四、基于时间戳的并发控制方法
- 4.1 基于时间戳顺序的调度规则
- 4.2 基于时间戳调度托马斯规则
- 五、基于有效性确认的并发控制方法
一、为什么要并发控制
多端操作同一个数据库的问题
1.2 并发控制解决的问题
1.2.1 脏读
新增的是行
1.2.2 幻读
修改的是原有数据的记录
1.2.3 不可重复读
1.2.4 数据丢失问题
并发控制、事务、封锁 是DBMS实现并发控制的核心技术
二、事务调度及可串行性
2.1 事务
DBMS提供的控制数据操作的一种手段,:应用程序员将一系列的数据库操作组合在一起为一个整体进行操作和控制,保证了一致性
2.1.1 事务的宏观
事务的宏观(应用程序员看到的事务):一个存取或改变数据库内容的程序的一次执行,或者说一个SQL组合的一次执行被看做一个事务。
由应用程序提出,有开始和结束,结束前需要提交或者撤销
Begin Transcation
exec sql...
...
exec sql...
exec sql commit work | exec sql rollback work
End Transcation
一段程序语句中,可能会存在执行循环,SQL引出事务,到Commit/Rollback结束事务,每次重复执行都会产生一个事务
2.1.2 事务的微观
DBMS看到的事务:对数据库的一系列基本操作(读写)的一个整体性执行
事务的并发执行: 多个事务从宏观上看是并行执行的,但是微观上的基本操作(R、W)是可以交叉执行的
2.1.3 事务的特性 ACID
原子性Atomicity:一组SQL操作是不可再分的
一致性Consistency:事务开始和结束时,数据库的完整性约束都存在。比如:每个银行账户>0 , 事务执行前后都应该>0
隔离性Isolation:多个并发事务之间的操作应该是互不干扰,每个事务独立运行。
持久性:一旦提交,结果就应该永久保存在数据库中。及时出现故障也不能丢失数据
2.2 事务调度与可串行性
事务调度:一组事务的基本步骤(R\W\其他控制操作加锁解锁等)的一种执行顺序称为对这组事务的一个调度。
并发(并行)调度:多个事务从宏观上看上去是并行执行的,但是微观上的基本操作(RW)是可以交叉执行的
并发调度的正确性:多个事务并发执行结果 === 每个事物依次执行的结果
并发调度的可串行性:一个调度的影响 === 某几个串行调度相同,则说 可串行化的 或 具有可串行性
冲突:调度中一一对连续的动作,如果他们顺序交换,那么涉及的事务中必须要改变。
有冲突的两个操作是不能交换次序的,没有冲突的两个事物是可以交换的。
事务可串行化是指对于任何两个或多个事务,
如果它们并发执行的结果和以某个序列化的顺序执行的结果是一样的,
那么这些事务就是可串行化的。
冲突可串行化是指对于任何两个或多个事务,
如果它们并发执行的结果和以某个序列化的顺序执行的结果是一样的,
且它们之间任何一个数据项的读写操作之间都没有冲突,
那么这些事务就是冲突可串行化的。
可串行化和冲突可串行化的区别在于,
可串行化只是要求不同的事务在并发执行和串行执行的结果是一致的,
而冲突可串行化要求不同事务之间的数据访问顺序不能引起冲突。
2.3 冲突可串行化判定
- 构造前驱图(有向图)
- 节点是每一个事物T。如果Ti的一个操作和Tj的一个操作发生冲突,Ti在Tj前面,则绘制一条边,由Ti指向Tj
- 测试检查:如果此有向图没没有环,那么冲突就是可串行的
三、基于封锁的并发控制方法
锁 是控制并发的一种手段
- 每一数据元素都有唯一的锁
- 事务读写前,要获取锁
- 后面的事务需要等待锁释放
- 事务处理完成后需要释放锁
3.1 锁的类型
3.1.1 共享锁Shared Lock
多个事务可以一起用共享锁,只能读取,不能修改
当数据有了排它锁,就不能再加共享锁
3.1.2 排它锁Exclusive Lock
一个事务独占排它锁,可以修改
3.1.3 意向共享锁 Intent Shared Lock
辅助锁,用来表明想要加上共享锁
3.1.4 意向排他锁 Intent Exclusive Lock
辅助锁,用来表明想要加上排它锁
3.1.5 更新锁Update Lock
也称为 共享更新锁,是一种介于 共享锁&排它锁 之间的锁
允许多个事务读取资源,但只允许一个事务进行修改
同样的,只能有一个更新锁,有了 更行锁 就不能加 共享锁
3.1.6 增量锁Incremental Lock
增量的 对 数据进行 lock & unlock
从而减少了锁冲突的概率,提升了并发性能
通常用于高并发场景下的资源访问控制
3.1.7 行级锁Row Lock
只锁定一行行的数据,而不锁定表的数据
3.1.8 表级锁Row Lock
锁定整个表
3.1.9 锁的优先级
排它锁 > 意向排它锁 > 意向共享锁 > 共享锁
行级锁 > 表级锁
3.2 加锁解锁时机
3.3 SQL隔离级别
3.3.1 读未提交 read uncommitted 0
可以读取其他事务未提交的数据,也就是允许脏读
最低的隔离级别,并发性最高,但是会导致数据不一致问题
3.3.2 读已提交 read committed 1
只能读取已经提交的数据,避免了脏读
但是在并发,多个事务同时访问一个数据,可能会出现重复读取的数据
3.3.3 可重复读 repeatable read 2
读取前,先加锁,其他事务不能修改
避免了重复读和脏读
3.3.4 可串行化 serializable 3
RW都会加锁,完全避免了并发
性能下降
封锁的粒度:
属性值 —> 元祖 —> 元祖集合 —> 整个关系 —> 整个DB
索引项 —> 整个索引
3.4 两段锁协议
加锁阶段Growing Pahse & 解锁阶段Shrinking Phase
访问前先申请锁
在提交前,所有的锁都不能释放
在加锁阶段,任何事务不能访问已经加锁的资源
银行转账,双方账户都锁定,转账才开始
四、基于时间戳的并发控制方法
4.1 基于时间戳顺序的调度规则
基于时间戳顺序的调度规则是根据事务提交的时间戳顺序进行调度,即按照时间戳先后顺序来决定事务执行的顺序
时间戳相同,就会导致死锁
此外,如果有多个事务同时竞争多个数据项,并且它们的时间戳相互依存,那么就可能出现死锁的情况。例如,如果事务1需要修改数据项A和B,而事务2需要修改数据项B和C,而时间戳1 < 时间戳2,那么事务1会先获得A和B的锁,但是无法获得C的锁,而事务2会先获得C的锁,但是无法获得B的锁,从而导致死锁的情况。
4.2 基于时间戳调度托马斯规则
托马斯规则要求事务按照它们的时间戳顺序提交,如果一个事务想要提交,但是有其他事务正在等待或已经占据它要修改的数据项,那么它必须等待所有占据该数据项的其他事务都提交或回滚后才能提交。托马斯规则的核心思想是通过强制事务按照一定的顺序提交,来保证不会出现死锁的情况。
五、基于有效性确认的并发控制方法
事务操作数据前,先确认没有其他事务正在操作
基于有效性确认的并发控制方法可以保证数据库的一致性和完整性,但它也会带来一定的性能开销,因为需要对每个事务所涉及到的数据项进行确认。此外,如果事务之间的竞争比较激烈,那么可能会导致较高的并发冲突率,影响系统的响应时间和处理能力。因此,在实际应用中,需要综合考虑并发控制方法的安全性和效率,选择合适的方法来满足系统的需求。