数据库学习笔记「并发控制」
前言
数据库是一个共享资源,可以供多个用户使用。
多用户数据库系统:允许多个用户同时使用同一个数据库的数据库系统
事务可以一个一个地串行之行,每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行。
为了充分利用系统资源,发挥数据库共享资源的特点,应该允许多个事务并行地执行
在这样的系统中,同一时刻并发运行的事务可以达到上百个
并发控制概述
事务是并发控制的基本单位
保证事务的ACID特性是事务处理的重要任务
⚠️多个事务对数据库的并发操作可能会造成事务ACID特性遭到破坏
为了保证事务的隔离性和一致性,数据库管理系统必须对并发操作进行操作
并发造型带来的数据不一致性
-
丢失修改(lost update)
两个事务\(T_!\)和\(T_2\)读入同一数据并修改,\(T_@\)提交的结果破坏了\(T_1\)提交的结果,导致\(T_1\)的修改丢失
-
不可重复读(non-repeatable read)
事务\(T_2\)读取数据后,事务\(T_2\)执行更新操作,使\(T_1\)无法再现前一次读取结果
-
读“脏”数据(dirty read)
事务\(T_1\)修改某一数据并将其写回磁盘,事务\(T_2\)读取同一数据后,\(T_1\)由于某些原因被撤销
这时被\(T_1\)修改过的数据恢复原值,\(T_2\)读到的数据就与数据库中的数据不一致
并发控制的主要技术有
- 封锁(locking)
- 时间戳(timestamp)
- 乐观控制(optimistic scheduler)
- 多版本并发控制(multi-version concurrency control)
封锁
封锁是实现并发控制的一个非常重要的技术
基本的封锁类型有两种:
-
排他锁(exclusive locks),简称X锁,又称写锁
若事务\(T\)对数据对象\(A\)加上X锁,则只允许\(T\)读取和修改\(A\)
其他事务都不能再对\(A\)加任意锁,直到\(T\)释放\(A\)
-
共享锁(share locks),简称S锁,又称读锁
若事务\(T\)对数据对象\(A\)加上S锁,则事务\(T\)可以读\(A\)但不能修改\(A\)
封锁协议
-
一级封锁协议
事务\(T\)在修改数据\(R\)之前先对其加X锁,直到事务结束才释放
- 可防止丢失修改
- 不能保证可重复读和不读“脏”数据
-
二级封锁协议
在一级封锁协议基础上增加事务\(T\)在读取数据\(R\)之前先对其加\(S\)锁,读完后再释放\(S\)锁
- 防止丢失修改,还可以进一步防止读“脏”数据
- 不能保证可重复读(读完即释放\(S\)锁)
-
三级封锁协议
在一级封锁协议的基础上增加事务\(T\),在读取数据\(R\)之前必须先对其加\(S\)锁,直到事务结束才释放
- 防止丢失修改,还可以进一步防止读“脏”数据、不可重复读
活锁和死锁
活锁
与操作系统的饥饿相似,事务处于永远等待
避免活锁的简单方法是采用先来先服务的策略
当多个事务请求封锁同一数据对象时,封锁子系统按请求封锁的先后次序对事务排队
死锁
与操作系统中的死锁同理,多个事务之间循环等待
目前数据库中解决死锁问题主要有两类方法:
-
采用一定措施来预防死锁的发生
死锁的预防:
- 一次封锁法:必须一次将所有要使用的数据全部加锁
- 顺序封锁法:预先对数据对象规定一个封锁顺序,所有事物都按这个顺序实施封锁
死锁的诊断与解除:
- 超时法:一个事务的等待时间超过了规定的时限,就认为发生了死锁
- 等待图法:动态地反映了所有事务的等待情况(检查是否有回路,有回落则死锁)
-
允许死锁发生,采用一定手段定期诊断系统中有无死锁,若有则解除