5.3 并发控制
5.3 并发控制
并发控制指在 DBMS 运行多个并发事务程序时,为确保各个事务独立正常运行,并防止相互干扰、保持数据一致性,所采取的控制与管理。
并发控制的目的
并发运行多个事务时,确保一个事务的执行不对另一个事务的执行产生不合理的影响,并解决可能产生的数据不一致、事务程序死锁等问题。(保证每个事务都满足ACID)。--- 等同于串行化的调度,可串行化
5.3.1 并发控制问题
在DBMS中,如果不对多个事务并发运行进行控制管理,数据库可能会产生若干数据不一致问题
下面各个例子中,事务A程序和事务 B程序共享访问雇员表(EMPLOYEE)数据。
1.脏读
读取共享数据的事务则读取得到一个垃圾数据,即脏数据。脏数据是对未提交的修改数据的统称。
【例】脏读
事务B将其年龄从18修改成20,事务A读取了Age=20,B又回滚了数据,使得Age=18,导致A获得一个脏数据
解决
但有的事务程序仅仅是读取了脏数据,并没有进行后续加工处理或使用,可以不理会它。
这样可以提高事务处理的并发性,减少事务的等待时间。
2.不可重复读
指一个事务对同一共享数据先后重复读取两次,但是发现原有数据改变或丢失。
【例】不可重复读
事务A第1次读取年龄小于等于20的 数据为3条。其后,事务B删除了一条数据。事务A程序再次读取雇员年龄小于等于20的数据时,数 据变为2条,使得事务A前后两次进行查询操作的结果不一致,即出现不可重复读问题。
3.幻像读
幻像读(Phantom Read)指一个事务对同一共享数据重复读取两次,但是发现第2次读取比第1次读取的结果中新增了一些数据。
原因:多个事务并发运行,其中一个事务同时在对共享数据进行添加操作。图5-10给出事 务并发运行可能出现幻像读的一个示例。
- 1、事务A程序第1次读取雇员年龄小于20的数据为2条。
- 2、其后,事务B程序在雇员表中新插入一套数据。
- 3、事务A程序再次读取雇员年龄小于20的数据时,数据变为3条,
- 则,事务A程序前后两次读取同一数据时出现不一致,即出现幻像读问题。
4.丢失更新
指一个事务对一共享数据进行更新处理,但是以后查询该值时,发现该数据与自己的更新值不一致。
原因:多个事务并发执行,其中一个事务对共享数据进行了更新,并改变了前面 事务的更新值。
- 1、事务A程序对雇员编号为A0001的年龄修改为19。
- 2、事务B程序也对其年龄修改为20。
- 3、事务A程序再次读取雇员编号为 A0001的数据,其年龄数据不是自己上次改的19,而是20
- 则,发现与此前修改的数据不一致,即出现所谓丢失更新问题。
5.3.2 并发事务调度
产生数据异常问题的根本原因:对共享数据的任意顺序的访问操作
确定执行顺序方案,以确保数据库一致性,由 DBMS 并发控制调度器实现
在DBMS中,假定有n个事务并发运行,这些事务在并发控制调度器中,有n!种串行调度执行顺序。
【例】这里给出T1和T2事务并发运行的4种调度顺序。只有第四种是错误的
可以得出结论:在事务并发运行中,只有当事务调度顺序的执行结果与事务串行执行的数据结果一样时,该并发事务调度才能保证数据库的一致性。
符合这样效果的调度 被称为可串行化调度。
因此,DBMS的并发控制调度器应确保并发事务调度是一种可串行化调度。
5.3.3 数据库锁机制
当多个并发事务以不同顺序对共享数据进行数据修改操作时,可能会带来数据不一致问题和并发事务之间的相互干扰问题。
资源锁定。 解决这些问题的基本办法是在每个事务更新、删除、新增共享数据 时,禁止其他事务同时访问共享数据副本,这种方法被称为资源锁定。
实现数据库资源锁定的技术原理如图
在DBMS中,锁定资源的类型
- 排他锁定(Lock-X)
- 锁定后,不允许其它事务对共享数据再加锁,限制其他事务访问
- 共享锁定(Lock-S)
- 锁定后,只允许其它事务对共享数据添加读取锁
数据库锁机制可以在多种粒度上对共享数据资源进行锁定处理。
资源锁定粒度
一般可以在 数据库(最大)、表、页面、行(最小)的粒度级别上进行资源锁定。
-
锁定的粒度越大,管理就越容易,但系统并发数据处理能力就越差。
-
锁定的粒度越小,管理就越复杂,但系统并发数据处理能力就越强。
资源锁定实施方式
- 隐式锁定——DBMS缺省执行
- 显式锁定——加锁命令显式执行
5.3.4 基于锁的并发控制协议
在并发事务运行中,事务可串行化调度是确保数据库一致性的基本方法。
为了实现并发事务在共享访问数据时可 以被串行化调度执行,需要约束事务对共享数据的操作访问必须以互斥方式进行。
可通过基于锁机制的并发控 制调度器执行一定的协议来实现。
解决共享数据的互斥访问
- 共享锁和排他锁
- 假定命名 D为共享数据
- 事务通过执行 Lock-S(D)指令来申请对数据D的共享锁定
- 事务通过执行Lock-X(D)指令来申请对数据D的排他锁定。
当 共享数据访问结束时,事务通过执行Unlock(D)指令来释放对数据D的锁定。
1.锁操作的相容性
没加锁,什么锁都能加
排他锁,加了锁就不能加其他的锁
加了共享锁,就能一直加共享锁
2.加锁协议
(1)一级加锁协议
修改之前,执行排他锁定指令,完成才解锁。(如果仅仅读数据,可以不加锁)
可以防止“丢失更新”的数据不一致问题。
【例】A=100,两边都是售出
未加锁,该调度流程的执行结果为A=99。
一级加锁协议,其调度执行结果为A=97。
(2)二级加锁协议
进行读操作前,执行共享锁定指令,读完数据即可释放共享锁定。
新加入了,撤回的情况
可以防止“丢失更新”的数据不一致问题,还可防脏读数据问题。
【例】A=100。T1撤回了一次
读取了脏数据 A=99, 空余机票数实际为100。
(3)三级加锁协议
在一级加锁协议基础上,读操作前,必须先对该数据执行共享锁定指令,直到事务处理结束才释放共享锁定。
可以防止“丢失更新”“脏读”的数据不一致性问题,还可防止出 现“不可重复读取”的数据一致性问题。
【例5-6】A为100
A=99,A=100,A=100
5.3.5 两阶段锁定协议
保证正确调度的前提是并发事务可串行化调度,保证可串行化的一个协议是:二阶段锁定协议
- 在增长阶段,事务可以加锁,但是不能解锁;
- 在缩减阶段,可以解锁,但是不能再加锁
【例5-7】假定两个事务T1和T2,均可将客户A转账200元到客户B账户。
a因其执行锁定申请和释放锁定操作时机不满足两阶段锁定协议,该事务可能无法实现可串行调度。
5.3.6 并发事务死锁解决
在基于锁机制的并发事务运行中,如果这些事务同时锁定两个及以上资源时,可能会出现彼此都不能继续运行的 状态,即事务死锁状态。
【例】假定两个事务T1和T2
死锁的必要条件
(1)互斥条件:一直占用资源,其他事务只能等待
(2)请求和保持条件:已经获得了资源并保持, 还需其他资源
(3)不剥夺条件:已获得的资源直到事务完成才自己释放,不能被剥夺
(4)环路等待条件:出现事务-资源等待环路
防范死锁的策略
用算法使系统尽量不出现死锁的条件
- 允许用户一次发出当前所需全部资源的锁定,使用完成后,再释放给其它用户访问。
- 规定所有应用程序锁定资源的顺序必须完全相同。
解决死锁问题的两类策略:
使产生死锁的4个必要条件之一不成立,
①预防死锁
②解除死锁。
预防死锁
在并发事务执行时,一般采用超时法或事务等待图法检测系统是否出现死锁。
解除死锁
如果出现了死锁,就需要将被死锁的事务进行资源解除处理。
通常选择一个处理死锁代价最小的事务进行撤销,释放该事务持有的所有锁定,使其他事务能够继续运行下去。
5.3.7 事务隔离级别
为了避免事务并发运行中可能出现的读脏、不可重复读、幻像读和丢失更新问题,可在DBMS中设置事务隔离级别 (Isolation Level)选项参数。
典型的DBMS支持4种事务隔离级别设置。不同的隔离级别可避免不同的事务并发问题, 具体见表5-3。
- 从上到下,隔离级别依次提高
- 由此可见,隔离级别越高,DBMS越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
- 隔离级别越低,系统并发性越高,出现问题的可能性也越高。
- 可串行化,yyds!
事务隔离级别设置是在DBMS中执行SET TRANSACTION命令来实现或通过管理工具设置。