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命令来实现或通过管理工具设置。

posted @   Dinesaw  阅读(263)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示