数据库中的并发控制和死锁活锁

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、事物并发可能带来的错误类型
  • 二、解决方法(可串行化)
    • 1.介绍
    • 2.封锁法(实现可串行化的方法之一)
    • 3.死锁和活锁
      • 方案


前言

在数据库中,并发控制,即允许多个事务同时对数据库进行访问
并发控制:

  • 提高系统利用率和响应时间
  • 不同的事物可能访问数据库不同的部分
  • 当多个事物访问到相同的部分时可能导致执行上的问题

一、事物并发可能带来的错误类型

读写和写写类型:可能导致的问题如丢失更新,读到脏数据,不可重复的读等问题

二、解决方法(可串行化)

1.介绍

可串行化是并发控制的一个标准,简单来说就是有n个事物,会有n!个执行结果,我们只要保证最终执行结果时n!中的一个,就说事物的并发控制是正确的

2.封锁法(实现可串行化的方法之一)

封锁法是决大多数并发控制的解决方法,锁是针对数据对象的,这里以关系为单位,实际上还可以对某个元组上锁等,引入三种封锁机制

  • X锁(排他锁)
    当事物T1给关系R上排他锁之后,这时候T2对R的读写是不允许的

封锁阶段(2PL):
在一个事物中,所有加锁请求都在解锁前面完成,即如下图,我们称这个限定为2PL数据库中的并发控制和死锁活锁_第1张图片
在一个事物中,对数据对象进行操作前,我们会寻求先上锁,这是一种好的表现,称为“well-formed"
如果有那么一个计划是满足2PL和well-formed的,我们称这个S计划是可串行化的,即可并操作。

  • S锁(共享锁)
    允许读,不允许写,S可以有多把。T1给R上了S,T2寻求对R的读,则给R也上S,这时候就可以访问R了。这时候对R的X是不允许的,即不允许修改。
  • U锁(更新锁)

对一个更新请求,我们先给上U锁,当真正需要到更新操作时,U锁升级为X锁。这样子可以缩短执行时间,提高并发程度。在U锁的基础上还可以上S锁,即真正修改更新前,我们还可以读操作。

三种锁的并发程度和负担数据库中的并发控制和死锁活锁_第2张图片

3.死锁和活锁

死锁:时间顺序上可以理解为T1对R1上X锁,T2对R2上X锁,这时候T2访问到R1,等待T1对R1解锁,处于等待中,但是此时T1也访问到R2,需要等待R2的解锁才可以进行R1的解锁,那么这两个事物就陷入了死循环。再通俗点的一个笑话:hr问你什么时死锁,你回答hr:“你给我offer我就告诉你什么时死锁"。
活锁,也叫饿死现象:尽管不存在死循环,但是等待时间过长数据库中的并发控制和死锁活锁_第3张图片

活锁是简单的,我们需要关注的是死锁,从预防和解决两个角度解决死锁问题

方案

  • 等待时间,给事物设置一个等待时间,当一个事物等待时间达到标准时,事物就会被废弃掉。这只适合小型的数据库,对数据库系统来说,如果等待时间设置的太短,会有无辜的事物被当成发生了死锁给处理掉,时间太长就检测不出死锁,效率低下。
  • 等待图,G是事物集合,V是等待时间,当图中出现环的时候,我们就可以认定出现了死锁现象,我们可以周期性检查等待图,或者每当有一个事物添加到图里面时就进行检查。
    当图中发生死锁时,我们会挑一个事物abort掉,使得rollback代价最小
  • 给事物中的关系一次性上锁,不然不执行,但是这样显然效率会很低下
  • 给资源顺序排序,然后在事物中上锁。但是这不符合数据库的应用,数据库中的数据是经常变动的修改的。我们给洗衣机,热水器,微波炉资源排序,如果一个人想要使用这三样,必须按照顺序来,先使用洗衣机,哪怕热水器空着,洗衣机有人在排队。
    - 时间戳,具体应用就是死亡等待和伤害等待,这也是在解决死锁方面常用的有效方案
    时间戳上简单概况包含了TID,即事物的ID,确保每个事物都是独一无二的和比较年龄
    死亡等待:a要用到r,但是b已经锁了r,这时候a和b比较,如果a比较老,就继续等待,a比较年轻的话,直接死掉,后面重启。我们要知道事物会随着时间的推移逐步进行的,即老事物的数量是有限的,新事物是无限的。某个事物年轻,脾气暴躁不能等,无法等到,经过几次重启后,他就会成为最老的,这时候就到他使用了。在他几次排队等待的时间上,后面的比他年轻,也得排在他后面
    伤害等待:年轻的等老的
    无论是哪种,我们都要确保这是单向的,在时间线上遵循同样的原则

你可能感兴趣的:(数据库,mysql)