详解mysql中的各类锁

一、存储引擎中锁的区别

    在介绍锁之前,我们先来了解下mysql的存储引擎。我们常用的存储引擎一般有两种,MyISAM和InnoDB,其中InnoDB最常用。至于两种存储引擎的特性我们就不在这里展开了,我们来看一下两种存储引擎里的锁有什么不同呢?

    1、MyISAM

     MyISAM里是表锁的形式。所谓表锁就是对整张表进行加锁,优点是它的开销小,加锁快;锁定粒度大,并且不会发生死锁。缺点是因为是对整张表进行加锁的,所以发生锁冲突的概率也是最高的,并发度也比较低。

     表锁又分为共享锁(读锁)排它锁(写锁);共享锁又称为读锁,也就是说针对同一个表操作,如果两个请求都是读请求的情况下,是不会互相影响的。但是如果其中一个是写操作的话,则会阻塞其他的写操作或读操作,直到锁释放为止。

     默认情况下,写锁比读锁具有更高的优先级:当一个锁释放时,这个锁会优先给写锁队列中等候的获取锁请求,然后再给读锁队列中等候的获取锁请求。这也正是 MyISAM 表不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。

   2.表级锁加锁方式

   了解了表锁后,我们来看一下MyISAM是如何进行加锁的呢?其实MyISAM 在执行查询语句(SELECT)前,会自动给涉及的表加读锁,在执行写操作
(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预。当然,mysql也提供了LOCK TABLE 命令给 MyISAM 表显式加锁。在自动加锁的情况下,MyISAM 总是一次获得 SQL 语句所需要的全部锁,这也正是 MyISAM 表不会出现死锁的原因。

   3.InnoDB

    说完了MyISAM,我们来说下InnoDB,InnoDB中既有表锁也有行锁。其中行锁也是分为共享锁(读锁)排它锁(写锁),只不过不同于表锁的是行锁的锁是作用于行数据,而不是作用于整张表。除此之外InnoDB还有意向共享锁意向排它锁,意向锁也是表级锁,为什么会有这两种锁呢?

    由于表锁和行锁虽然锁定范围不同,但是会相互冲突。所以当你要加表锁时,势必要先遍历该表的所有记录,判断是否加有排他锁。这种遍历检查的方式显然是一种低效的方式,MySQL 引入了意向锁,来检测表锁和行锁的冲突。

    当事务要在记录上加上读锁或写锁时,要首先在表上加上意向锁。这样判断表中是否有记录加锁就很简单了,只要看下表上是否有意向锁就行了。意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。意向锁是InnoDB自动加的,不需要用户干预。

    4.行级锁加锁方式

     共享锁:

             对于普通的查询语句是不会加锁的,列如 select * from user;

             对于有查询条件的语句,如果查询条件中有索引列,则使用行锁,如果查询条件非索引列,则使用表锁。

             显示加锁:SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE

     排它锁:

             对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;

            显示加锁:SELECT * FROM table_name WHERE ... FOR UPDATE

    5.间隙锁

      间隙锁产生的原因是因为Query执行过程中通过范围查找的话,它会锁定整个范围内所有的索引键值,即使这个键值并不存在。

      例:假如user表中只有101条记录,其id的值分别是 1,2,…,100,101,下面的SQL:

mysql> select * from user where id > 100 for update;

      是一个范围条件的检索,InnoDB不仅会对符合条件的id值为101的记录加锁,也会对id大于101(这些记录并不存在)的“间隙”加锁。当然间隙锁的好处主要是防止防幻读。此时如果还能插入一条102的数据,则会导致幻读。缺点是在插入频繁的操作使用不当会造成大量阻塞,所以我们要尽量避免这种范围条件。

     6.死锁

  • 死锁产生:
    • 死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环。
    • 当事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一个资源时也可能会产生死锁。
    • 锁的行为和顺序和存储引擎相关。以同样的顺序执行语句,有些存储引擎会产生死锁有些不会——死锁有双重原因:真正的数据冲突;存储引擎的实现方式。
  • 检测死锁:数据库系统实现了各种死锁检测和死锁超时的机制。InnoDB存储引擎能检测到死锁的循环依赖并立即返回一个错误。
  • 死锁恢复:死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁,InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。所以事务型应用程序在设计时必须考虑如何处理死锁,多数情况下只需要重新执行因死锁回滚的事务即可。
  • 外部锁的死锁检测:发生死锁后,InnoDB 一般都能自动检测到,并使一个事务释放锁并回退,另一个事务获得锁,继续完成事务。但在涉及外部锁,或涉及表锁的情况下,InnoDB 并不能完全自动检测到死锁, 这需要通过设置锁等待超时参数 innodb_lock_wait_timeout 来解决
  • 死锁影响性能:死锁会影响性能而不是会产生严重错误,因为InnoDB会自动检测死锁状况并回滚其中一个受影响的事务。在高并发系统上,当许多线程等待同一个锁时,死锁检测可能导致速度变慢。 有时当发生死锁时,禁用死锁检测(使用innodb_deadlock_detect配置选项)可能会更有效,这时可以依赖innodb_lock_wait_timeout设置进行事务回滚。
  • 死锁预防:可以尽量在不同的事物中指定操作顺序,达到事物顺序一致,来避免多个事物同一资源的互相占用

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值