MySQL 锁

目录

前言

锁类型

按照操作类型划分

1. 读锁

2. 写锁

3. 意向锁

按照颗粒度划分

1. 表锁

2. 行锁

3. 页锁

4. 间隙锁

5. 临键锁

锁之间兼容性

死锁

死锁的原因

如何避免死锁

死锁的解决

总结


前言


        在之前的文章有多次提到,MySQL在数据更新和性能优化上会用到锁机制。我们在实际的应用中也经常会遇到锁相关的问题,即使很多时候我们并没有人为的为数据库添加锁,但还是会出现死锁的问题,这是因为在我们操作数据时MySQL隐式的帮我们加了锁。

这篇文章主要讲一下MySQL锁的类型和锁与锁之间的关联。

锁类型

按照操作类型划分

1. 读锁

        读锁也叫共享锁(S 锁),它是一种读共享写阻塞的锁,当对表里的某一行数据添加S锁时,其他事务对其写时会阻塞,但可以对它进行读操作。同时其他事务可以对该数据添加S锁,但不能添加X锁。因此S锁和S锁可兼容,S锁和X锁不能兼容。

2. 写锁

        写锁也叫排他锁(X 锁),它是一种对任何锁都阻塞的锁,当对表里的某行数据添加X锁时,其他事务时不允许再对它添加S锁和X锁。

3. 意向锁

        意向锁是表级锁,又分为意向读锁(IS 锁)和意向写锁(IX 锁),它是基于在InnoDB存储引擎下的一种锁,意向锁无法手工添加,是由存储引擎自动添加的。

        当事务操作需要获取数据行的锁时,首先需要先获取表对应的意向锁。当需要对表添加表级的锁时,会判断是否存在意向锁,而不用每一行判断是否有行锁,这样可以大大提高数据库的性能。
        意向锁之间是相互兼容的,它们相互之间不会阻塞对方获取锁。

按照颗粒度划分

1. 表锁

        针对表操作的锁,MyISAM存储引擎下目前只支持表锁。对表进行加锁,加锁速度快、锁的颗粒大、不会出现死锁。但是容易出现锁冲突,性能要低,容易造成阻塞,并发度低。

2. 行锁

        针对数据行操作的锁,InnoDB存储引擎下支持表锁和行锁。加锁的速度慢需要查找到对应的数据行,锁颗粒度小,容易出现死锁,并发度高。当需要对数据进行检索操作时最好能够使用索引,避免全表扫描,如果是全表扫描那么行锁即变为表锁。

3. 页锁

        针对数据页操作的锁,是基于BerkeleyDB存储引擎的锁,锁定的颗粒度介于行锁与表锁之间,所以它的并发度和资源的开销也是介于行锁与表锁之间。

4. 间隙锁

        当检索条件为范围检索,它会对锁定该检索条件的这个范围,但并不会对记录本身进行加锁,这个就叫做间隙锁。

        间隙锁只有在RR隔离级别以上才支持,它也是MVCC解决幻读问题的一个重要支持。间隙锁和间隙锁质检可以兼容,也就是两个事务可以同时持有同一范围的间隙锁。

        举例:

        user表:

idnameage
1张三18
2李四30

      1. 当使用精确检索时

        事务1:

        select * from user where age=18 and age=30 for update;

        事务2:

        insert into user(name,age) values('王五',20);

        这种情况下事务1精确检索,只会对这两行数据进行加锁,因此事务2可正常执行。

        2. 当使用范围检索时

        事务1:

        select * from user where age>=18 and age<=30 for update;

        事务2:

        insert into user(name,age) values('王五',20);

       事务1使用范围检索,InnoDB会对这两行数据进行加锁同时也会对18到30之间的间隙也加锁,因此事务2将会阻塞不可执行。

        间隙锁的引入是为了解决在RR隔离级别的幻读问题。

5. 临键锁

        临键锁(Next-Key Lock ),它比间隙锁多了就是可以对记录本身进行加锁,它不仅锁定了检索的范围,也锁定了记录的本身行,它也是为了解决幻读的问题。

锁之间兼容性

共享锁排他锁意向共享锁意向排他锁
共享锁兼容互斥兼容互斥
排他锁互斥互斥互斥互斥
意向共享锁兼容互斥兼容兼容
意向排他锁互斥互斥兼容兼容

       从以上表格中可以看出排他锁与任何锁都不兼容,共享锁只与共享锁兼容,意向锁之间都兼容。

死锁

死锁的原因

        死锁产生的原因一般有以下几个:

        1. 多个事务在并发执行过程中,因争夺资源而造成的一种互相等待的现象。

        2. 加锁的顺序相反导致。

        3. 因锁冲突导致死锁。

如何避免死锁

  • 对并发高的场景下,尽可能使用RC的隔离级别。
  • SQL操作语句,尽可能使用索引,减少加锁的范围。
  • 尽可能降低事务,不要使用大事务,减少锁资源的占用。
  • 访问量大时需要多做数据库主从,将数据库的访问分摊到不同的机器中。

死锁的解决

        可以通过以下语句查看锁的状态,最终找到相应产生死锁相应的进程,人工kill该进程释放锁的状态。

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

总结

        MySQL中存在不同颗粒度的锁,从小到大有,行锁、间隙锁、页锁、表锁,锁的颗粒度越大消耗的资源越小,但并发度越低。不同的存储引擎对锁的实现也不一样。InnoDB支持行锁、间隙锁和表锁,MyISAM只支持表锁,BerkeleyDB支持页锁和表锁。

        锁的添加是需要消耗资源的,如果锁添加的越多性能就会相应的降低,同时也会出现锁冲突或者是死锁的情况,所以在实际的应用中根据实际情况加锁,不要盲目的添加从而造成系统性能降低甚至崩溃。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值