Mysql锁

锁的分类

  • 基于锁的属性分类:共享锁、排它锁。
  • 基于锁的粒度分类:表锁、行锁、记录锁、间隙锁、临键锁。
  • 基于锁的状态分类:意向共享锁、意向排它锁。

排他锁与任何的锁都不兼容,共享锁仅和共享锁兼容。由于MVCC的存在,对于一般的SELECT语句,InnoDB不会加任何锁。不过, 你可以通过语句显式加共享锁或排他锁。

  • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响

当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

  • 写锁(排他锁):当前写操作没有完成前,会阻断其他写锁和读锁

当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取。避免了出现脏数据和脏读的问题。

S 锁X 锁
S 锁不冲突冲突
X 锁冲突冲突
  • 表锁:锁住被操作的整张表

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小,所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,是针对非索引字段加的锁,所以可以很好的避免困扰我们的死锁问题。当然,锁定颗粒度大所带来最大的负面影响就是锁资源竞争(死锁)的概率也会最高,致使并发度大打折扣。使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。

  • 行锁:锁住被操作表中的被操作行,其他行不受影响

行级锁定最大的特点就是锁定对象的粒度很小,是针对索引字段加的锁,只对当前操作的行记录进行加锁。由于锁定颗粒度很小,所以发生锁资源竞争的概率也小,并发度高。但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。使用行级锁定的主要是InnoDB存储引擎。

InnoDB 有哪几类行锁

InnoDB行锁是通过对索引数据页上的记录加锁实现的,InnoDB支持三种行锁定方式:

  • 记录锁(Record Lock):属于单个行记录上的锁。记录锁是说事务在加锁后锁住的只是表的某一条记录。
    • 触发条件:精准条件命中,并且命中的条件字段是唯一索引。
    • 作用:加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。
  • 间隙锁(Gap Lock):间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。
    • 触发条件:范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。
    • 作用:防止幻读问题,事务并发的时候,如果没有间隙锁,在同一个事务里,一个事务的两次查询出的结果会不一样。
  • 临键锁(Next-Key Lock):Record Lock+Gap Lock,锁定一个范围,包含记录本身,主要目的是为了解决幻读问题。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。总结来说它就是记录锁和间隙锁的组合。
    • 触发条件:范围查询并命中,查询命中了索引。
    • 作用:结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。

InnoDB默认的隔离级别REPEATABLE-READ下,行锁默认使用的是Next-Key Lock。但是,如果操作的索引是唯一索引或主键,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。

行级锁的使用有什么注意事项

InnoDB的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的锁。当我们执行UPDATEDELETE语句时,如果WHERE条件中字段没有命中唯一索引或者索引失效的话,就会导致扫描全表对表中的所有记录加锁。不过,有时候因为MySQL优化器的原因,即使用了索引也有可能会走全表扫描。

意向锁有什么作用

如果需要用到表锁的话,如何判断表中的记录没有行锁呢?一行一行遍历肯定是不行,性能太差。我们需要使用意向锁来快速判断是否可以对某个表使用表锁。

意向锁是表级锁,共有两种:

  • 意向共享锁(Intention Shared Lock,IS 锁):事务有意向对表中的某些记录加共享锁(S 锁),加共享锁前必须先取得该表的IS锁。
  • 意向排他锁(Intention Exclusive Lock,IX 锁):事务有意向对表中的某些记录加排他锁(X 锁),加排他锁之前必须先取得该表的IX锁。

意向锁是由数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前,InnoDB会先获取该数据行所在在数据表的对应意向锁。意向锁之间是互相兼容的。

IS 锁IX 锁
IS 锁兼容兼容
IX 锁兼容兼容

意向锁和共享锁和排它锁互斥(这里指的是表级别的共享锁和排他锁,意向锁不会与行级的共享锁和排他锁互斥)。

IS 锁IX 锁
S 锁兼容互斥
X 锁互斥互斥

当前读和快照读有什么区别

快照即记录的历史版本,每行记录可能存在多个历史版本。快照读的情况下,如果读取的记录正在执行UPDATE/DELETE操作,读取操作不会因此去等待记录上X锁的释放,而是会去读取行的一个快照。

只有在事务隔离级别RC(读取已提交) 和RR(可重读)下,InnoDB才会使用一致性非锁定读:

  • 在RC级别下,对于快照数据,一致性非锁定读总是读取被锁定行的最新一份快照数据。
  • 在RR级别下,对于快照数据,一致性非锁定读总是读取本事务开始时的行数据版本。

快照读比较适合对于数据一致性要求不是特别高且追求极致性能的业务场景。当前读 (一致性锁定读)就

死锁

死锁是指两个或多个事务在执行过程中,因争夺锁资源而造成的相互等待的现象,若无外力干涉它们都将无法继续执行。通俗来说,就是两个或多个事务在等待对方释放锁,从而造成僵持不下,使得整个系统陷入停滞状态。

如何减少死锁

  • 尽量使用较低的隔离级别; 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会;
  • 选择合理的事务大小,小事务发生锁冲突的几率也更小;
  • 给记录显式加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁;
  • 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会;
  • 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响; 不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁;
  • 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。

间隙锁的弊端

  1. 性能影响:间隙锁会阻止其他事务在已经锁定的范围内插入新的行,这可能会显著影响数据库的并发性能,尤其是在需要大量插入操作的高并发场景下。
  2. 死锁风险:虽然间隙锁在某些情况下可以防止死锁,但在其他情况下,它可能会增加死锁的风险。
  3. 幻读问题:间隙锁主要用于防止幻读现象,确保事务的隔离级别达到可重复读。然而,间隙锁只锁定范围,不锁定具体的索引记录或行,这可能导致在事务执行过程中,其他事务仍然可以在间隙中插入新记录,从而破坏事务的一致性。
  4. 插入操作受阻:当锁定一个范围键值之后,即使某些不存在的键值也会被锁定,导致在锁定的时候无法插入锁定键值范围内的任何数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值