mysql面试题——锁相关

一:InnoDB的锁机制?

为保证数据的一致性,需要对并发操作进行控制 ,因此产生了 锁 。同时锁机制也为实现MySQL的各个隔离级别提供了保证。

二:什么是排他锁和共享锁?

共享锁(读锁):针对同一份数据,多个事务的读操作可以同时进行而不会互相影响,但任何事务都不能对数据进行修改,直到已释放所有共享锁。
排他锁(写锁):如果一个事务对数据A加上排他锁后,则其他事务不能再对A加任任何类型的锁。获得排他锁的事务既能读数据,又能修改数据。

三:表级锁、行级锁、页级锁的描述与特点

表级锁:对当前操作的整张表加锁

  1. 表级别的S锁、X锁
    LOCK TABLES t READ :InnoDB存储引擎会对表 t 加表级别的 S锁 。
    LOCK TABLES t WRITE :InnoDB存储引擎会对表 t 加表级别的 X锁 。
    对一个表加上读锁:
    对一个表加上写锁:在这里插入图片描述
    总结:MyISAM在执行查询语句,会给涉及的所有表加读锁,在执行增删改操作之前,会给 涉及的表加写锁。InnoDB存储引擎是不会为这个表添加表级别的读锁或者写锁
  2. 意向锁

行级锁:只针对当前操作的行进行加锁

  1. 记录锁:记录锁也就是仅仅把一条记录锁上
    记录锁是有S锁和X锁之分的,称之为 S型记录锁 和 X型记录锁 。
    (1)当一个事务获取了一条记录的S型记录锁后,其他事务也可以继续获取该记录的S型记录锁,但不可以继续获取X型记录锁;
    (2)当一个事务获取了一条记录的X型记录锁后,其他事务既不可以继续获取该记录的S型记录锁,也不可以继续获取X型记录锁。
    在这里插入图片描述

  2. 间隙锁( gap锁):不允许别的事务在id值为8的记录前边的间隙插入新记录
    在这里插入图片描述
    图中id值为8的记录加了gap锁,意味着 不允许别的事务在id值为8的记录前边的间隙插入新记录 ,其实就是id列的值(3, 8)这个区间的新记录是不允许立即插入的。比如,有另外一个事务再想插入一条id值为4的新记录,它定位到该条新记录的下一条记录的id值为8,而这条记录上又有一个gap锁,所以就会阻塞插入操作,直到拥有这个gap锁的事务提交了之后,id列的值在区间(3, 8)中的新记录才可以被插入。
    gap锁的提出仅仅是为了防止插入幻影记录而提出的。

  3. 临键锁:我们既想锁住某条记录 ,又想阻止其他事务在该记录前边的间隙插入新记录 ,所以InnoDB就提出了这种锁
    存储引擎 innodb 、事务级别在可重复读的情况下使用的数据库锁

     begin;
     select * from student where id <=8 and id > 3 for update;
    

页级锁:页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。

四:什么是意向锁?

现在有两个事务,分别是T1和T2,其中T2试图在该表级别上应用共享或排它锁,如果没有意向锁存在,那么T2就需要去检查各个页或行是否存在锁;如果存在意向锁,那么此时就会受到由T1控制的表级别意向锁的阻塞。T2在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。
为了解决这个问题,MySQL引入了意向锁机制。当一个事务请求获取一个行级锁或表级锁时,MySQL会自动获取相应的表的意向锁。意向锁有两种类型:意向共享锁和意向排他锁。意向锁是表级锁,不会和行级的X,S锁发生冲突,只会和表级的X,S发生冲突
意向共享锁:事务有意向对表中的某些行加共享锁
意向排他锁:事务有意向对表中的某些行加排他锁
五:

六:什么是乐观锁与悲观锁?

乐观锁和悲观锁并不是锁,而是锁的设计思想

七:乐观锁与悲观锁如何实现?

悲观锁:会通过数据库自身的锁机制来实现,在InnoDB引擎中,要使用悲观锁,需要先关闭MySQL数据库的自动提交属性,然后通过select … for update 来进行加锁。
例子:下单过程中扣减库存的需求说明一下如何使用悲观锁

	1.开始事务
	begin;
	2.查询出商品信息
	select quantity from items where id-1 for update;
	3.修改商品quantity为2
	update items set quantity=2 where id = 1;
	4.提交事务
	commit;

在对id = 1的记录修改前,先通过for update的方式进行加锁,然后再进行修改。这就是比较典型的悲观锁策略。
注意事项:select … for update语句执行过程中所有扫描的行都会被锁上,因此在MysQL中用悲观锁必须确定使用了索引,而不是全表扫描,否则将会把整个表锁住。

乐观锁:不采用数据库自身的锁机制,主要通过CAS的机制来实现,一般通过version版本号来实现。
例子:在表中设计一个 版本字段 version ,第一次读的时候,会获取 version 字段的取值。然后对数据进行更新或删除操作时,会执行 UPDATE … SET version=version+1 WHERE version=version 。此时如果已经有事务对这条数据进行了更改,修改就不会成功。

七:其他锁

全局锁: 整个数据库实例加锁,当你需要让整个库处于只读状态 的时候,可以使用这个命令,之后数据更新语句、数据定义语句和更新类事务的提交语句会被阻塞。
适用场景: 全库逻辑备份 。
死锁:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。
在这里插入图片描述
这时候,事务1在等待事务2释放id=2的行锁,而事务2在等待事务1释放id=1的行锁。 事务1和事务2在互相等待对方的资源释放,就是进入了死锁状态。

八:数据库死锁如何解决?

  1. 直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout 来设置。
  2. 发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务(将持有最少行级排他锁的事务进行回滚),让其他事务得以继续执行

九:数据库如何避免死锁?

  1. 合理设计索引,使业务SQL尽可能通过索引定位更少的行,减少锁竞争
  2. 降低隔离级别:比如使用RC来代替RR来避免因为gap锁和next-key锁而带来的死锁情况。
  3. 固定顺序访问数据:事务在访问同一张表时,应该以相同的顺序获取锁,这样可以避免死锁目的发生。
  4. 减少锁的时长:加快事务的执行速度,降低执行时间,也能减少死锁发生的概率。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值