MySQL 锁

一、全局锁

在做全库备份时,为了保证数据一致性,会给数据库加上全局锁

#开启全局锁
flush tables with read lock;
#shell下运行
mysqldump -h domain/ipaddr -P 3306 -u root -p123456 dbname > filename
#释放全局锁
flush tables with read lock;

在加上全局锁后,只能进行读操作,不能写操作,因此业务几乎处于停摆状态。即使是在从库上备份,在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。

在InnoDB引擎中,可以在备份时加上参数 --single-transaction, 参数来完成不加锁的一致性数据备份(底层是快照读的方式实现的)。

#shell下运行
mysqldump --single-transaction -h domain/ipaddr -P 3306 -u root -p123456 dbname > filename

二、表级锁

表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中。表级锁主要分为以下三类:

  • 表锁
  • 元数据锁(meta data lock, MDL)
  • 意向锁

1、表锁

对于表锁,分为两类:

  • 表共享读锁(read lock)
  • 表独占写锁(write lock)
#开启读锁或写锁
lock tables tablename read/write;
#释放锁,执行以下命令或直接关闭客户端
unlock tables;

开启读锁后,所有人(客户端)只能查询该表的数据,不可进行写操作。执行此命令的客户端,若进行写操作,将会报错提示该表加了读锁;而其他人做写操作时,将会进入阻塞(等待)状态,直至读锁被释放。

开启写锁后,执行此命令的客户端,可进行读写操作;其他客户端的读写操作将会阻塞。

2、元数据锁

元数据锁(meta data lock),简写MDL。可简单理解为表结构锁。
当某个表存在事务活动时,会自动开启元数据锁,此时无法进行表结构修改(alter table语句),进入阻塞状态;当事务提交后,锁会自动释放。

#查询当前存在的元数据锁
select object_type, object_schema, object_name, lock_type, lock_duration
from performance_schema.metadata_locks;

3、意向锁

  • 意向共享锁(IS): 由语句 select … lock in share mode 添加 。与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。
  • 意向排他锁(IX):由insert、update、delete、select…for update添加。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。
#IS手动添加,IX自动添加
select * from table where id = 1 lock in share mode;

添加IS后,可加读锁,不可加写锁;
添加IX后,读锁与写锁均不能添加。

三、行级锁

行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。
InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。
行级锁,主要分为以下三类:

  • 行锁
  • 间隙锁
  • 临键锁。

1、行锁

行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行 update 和 delete。在RC(读已提交)、RR(可重复读)隔离级别下都支持。

InnoDB实现了以下两种类型的行锁:
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。一行可以存在多个共享锁。
排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

  • select:不加锁
  • select …… lock in share mode:共享锁
  • select …… for update、insert、delete、update:排他锁

2、间隙锁 & 临键锁

间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR(可重复读)隔离级别下都支持
临键锁(Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。 在RR(可重复读)隔离级别下支持

默认情况下,InnoDB在 REPEATABLE READ 事务隔离级别运行,InnoDB使用 next-key锁(临键锁)进行搜索和索引扫描,以防止幻读。
间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。

  • 索引上的等值查询(唯一索引),给不存在的记录加锁时, 优化为间隙锁。
  • 索引上的等值查询(非唯一普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。
  • 索引上的范围查询(唯一索引)会访问到不满足条件的第一个值为止。

拓展——死锁

在MySQL中,死锁(Deadlock)指的是两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致一个僵局。当这种情况发生时,没有一个事务能够继续执行,因为它们都在等待其他事务释放所需的资源。由于这种相互等待的情况,事务都无法继续执行,从而形成了一个“死锁”。

死锁的常见场景包括:

  • 多个事务并发执行:当多个事务试图同时访问和修改相同的数据时,可能会出现死锁。
  • 不一致的锁定顺序:如果两个事务试图以不同的顺序锁定资源,也可能导致死锁。例如,事务A锁定了资源1并试图锁定资源2,而事务B锁定了资源2并试图锁定资源1。
  • 隐式锁:在MySQL InnoDB存储引擎中,行级锁是隐式获得的,当两个事务都试图修改同一行数据时,可能会产生死锁。

为了避免死锁,可以采取以下策略:

1. 一致的锁定顺序:确保所有事务都按照相同的顺序请求锁。
2. 锁超时:设置合理的锁超时时间,这样当事务等待锁超过指定时间后,它会自动放弃,从而避免长时间的死锁。
3. 减小事务大小:尽量减小事务的范围和持续时间,这样可以减少锁的竞争。
4. 避免用户输入导致的死锁:例如,可以通过应用程序逻辑来确保用户不会同时提交冲突的操作。
5. 监控和日志记录:通过监控工具来检测死锁,并记录日志以便后续分析。

如果发生死锁,数据库管理系统(DBMS)通常会选择一个事务作为“牺牲者”来中止,从而解决死锁,这样其他事务就可以继续执行。在MySQL中,InnoDB存储引擎有自己的死锁检测机制,当检测到死锁时,它会自动中止一个或多个事务来打破死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值