MySQL事务并发控制(再也不怕面试官问MySQL了)

MySQL事务并发控制(再也不怕面试官问MySQL了),第1张

MySQL事务并发控制(再也不怕面试官问MySQL了)

大纲
  • 事务
  • ACID特性
  • MySQL实现事务
  • 事务并发运行带来的问题
    • 并发调度可能引发的问题:
  • 如何解决事务并发带来的问题
    • 锁的分类
    • 封锁协议
      • 一级封锁协议:
      • 二级封锁协议:
      • 三级封锁协议:
    • 两段锁协议
    • 封锁协议带来的问题
      • 死锁

事务

事务是一个不可再分的工作单位;事务中的一系列 *** 作要么全部执行,要么全不执行;其中,事务满足ACID特性

ACID特性

原子性(Atomicity):对数据的修改要么全部执行,要么全不执行

一致性(Consistency):事务执行前和执行后数据库必须满足一致性(事务执行过程中可以不满足)。例如从账户A中取款,取款前和取款后都必须满足取款金额加账户余额是一致的。

隔离性(Isolation):事务之间要相互隔离,即一个事务内部的 *** 作和修改的数据不应该被别的事务看到,而应该封锁起来。

​ 在MySQL中,隔离级别有四个

​ 1.读未提交:会读到脏数据;例如事务A正在修改某数据,而且还没提交,所以还没提交的中间数据是不应该被别的事务读到的,也就是脏的。

​ 2.读已提交:不会读到脏的数据,但不能重复读

​ 3.可重复读:可以重复读,但可能会有幻读(MySQL的默认级别)

​ 4.串行化:事务A和事务B,事务A在 *** 作数据库时,事务B只能排队等待,这种隔离级别很少用。

持久性(Durability):提交的事务的更新不能消失,就是要持久地存放到磁盘里。

MySQL实现事务
mysql> start transaction;#手动开启事务
  mysql> insert into t_user(name) values('pp');
  mysql> commit;#commit之后即可改变底层数据库数据
  mysql> select * from t_user;
  +----+------+
  | id | name |
  +----+------+
  |  1 | jay  |
  |  2 | man  |
  |  3 | pp   |
  +----+------+
  3 rows in set (0.00 sec)
事务并发运行带来的问题

事务的的调度通常分为串行调度和并发调度。

串行调度:在调度过程中,单个事务的指令紧挨着一起,各个事务以此执行。

并发调度:最常用的调度方式,如果调度不当,会破坏事务的ACID特性。

并发调度可能引发的问题:
  1. 丢失更新

    Tj事务对数据的更新破了了Ti提交的新的更新,导致了Ti丢失了更新

  2. 脏读

    读取了不一致或不存在的数据

  3. 不可重复读

    某事务读取数据两次取值不同

如何解决事务并发带来的问题

首先需要明确,所有事务串行起来的调度策略一定是正确的调度策略。所以,只需要保证并发调度的结果与某串行策略的结果一致(可串行化策略),就可以保证并发事务的正确性。

锁的分类
  1. 共享锁(S锁):多个事务可以对同一个对象加多个S锁,但不能加排他锁。确保多个事务可以同时读同一个对象。

  2. 排他锁(X锁):同一个对象只接收一个事务加一个排他锁,直至这个事务释放该锁前,其它事务不能加任何锁。

  3. 更新锁(U锁): 一次只有一个事务可以获得更新锁,更新锁与共享锁兼容,与排他锁不兼容。更新锁可以防止常见的死锁,例如两个事务同时持有同一对象的共享锁,但两个线程都想对数据进行修改,那么他们需要把持有的共享锁换为排他锁,但由于双方都持有共享锁,他们互相等待对方释放共享锁从而导致了死锁现象。如果事务持有一个对象的更新锁,他若要修改数据更新锁则变为排他锁,若只读数据则更新锁可以看成共享锁。下面有例子:

    T1:    select * from table(updlock)    (加更新锁)  
    T2:    select * from table(updlock)    (等待,直到T1释放更新锁,因为同一时间不能在同一资源上有两个更新锁)  
    T3:    select * from table (加共享锁,但不用等updlock释放,就可以读)  
      
    这个例子是说明:共享锁和更新锁可以同时在同一个资源上。这被称为共享锁和更新锁是兼容的。  
    
  4. 意向锁: 是一种不与行级锁冲突表级锁,若要获取某些行的S锁或者X锁,就需要获取对应的IS和IX意向锁。意向锁是有数据引擎自己维护的,用户无法手动 *** 作意向锁,在为数据行加共享 / 排他锁之前,InooDB 会先获取该数据行所在在数据表的对应意向锁。需要注意的是,意向锁不会与行级的排他/共享锁互斥。

图中的共享锁和排他锁指的是表锁,而不是行锁。意向锁存在的意义是,当有需要为一个表上一个排他的表锁时,只需要判断意向锁是否被获取,而不是逐行检测是否有行级锁,提高效率。如果意向锁被获取了,则阻塞等待。

封锁协议

含义:封锁协议是事务什么时候加锁、释放锁、持有锁持有多久等的一些规定。封锁协议用来解决丢失更新、脏读、不可重复读等问题

一级封锁协议:

事务在修改数据前需要对其加排他锁(X锁),直到事务结束才释放(包括正常的提交和回滚)。因为持有了更细数据的排他锁,所以该数据不会被别的事务修改,从而解决了更新丢失的问题。

二级封锁协议:

在一级封锁协议的基础上,事务在读取数据前,先为其加上共享锁(S锁),读完就马上释放掉。因为如果要读的数据正在被另外事务修改,那么另外的事务会持有该对象的排他锁,从而本事务不能在该对象上加共享锁,从而读不了脏的数据,解决了脏读问题。

三级封锁协议:

在一级封锁协议的基础上,事务在读取数据前,先为其加上共享锁(S锁),但并不是读完就释放,而是等事务结束后再释放,从而在事务没有结束前,该数据无法被修改,从而可以重复读取,解决了不可重复读的问题。

两段锁协议

虽热三级封锁协议解决了并发事务的三个问题(更新丢失、脏读、不可重复读),但却并不能保证并发事务是可串行化的。

含义:所谓的两段锁协议,其实就是所有的事务都必须遵循两个阶段获取锁和释放锁:第一阶段,任何事务都可以获取锁,但不能释放锁;第二阶段,所有事务都可以在此阶段释放锁,但不能申请锁。下图事务1遵循两段锁协议,事务2不遵循。

事务遵循两段锁协议是可串行化调度的充分不必要条件。

封锁协议带来的问题

虽然三级封锁协议解决了并发事务的三个问题,而两段封锁协议也解决了并发事务调度的可串行化问题,但可能会发生死锁的问题

死锁

含义:事务1持有了对象A的锁而想去获取B的锁,而同时事务2持有了B的锁而它想去获取A的锁;从而两个事务进入了无限相互等待。

解决方法:用一次封锁法(先把要加的锁都加完)、顺序封锁法(所有的数据排一个顺序,封锁按照这个顺序来),在数据库中以上两种方法维护成本高,所有通常用诊断法来解决。而诊断法分为超时法和等待图法(类似于图论中的判断一个图是否有回路)。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5680772.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存