mysql 锁
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了mysql 锁,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4165字,纯文字阅读大概需要6分钟。
内容图文
![mysql 锁](/upload/InfoBanner/zyjiaocheng/859/53ce13add3bb44cfb9554927c41d4e5c.jpg)
一、全局锁
全局锁:所有的表都变成只读状态,数据更新或者字段更新将会被阻塞;
使用场景:全局锁一般用在整个库(包含非事务引擎表)做备份(mysqldump 或者xtrabackup)时,也就是说,在整个备份过程中,整个库都是只读的,其实这样风险挺大的。如果是在主库备份,会导致业务不能修改数据;而如果是在从库备份,就会导致主从延迟;
drop table if exists t14;
CREATE TABLE `t14` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into t14(a,b) values(1,1);
MySQL 全局锁会关闭所有打开的表,并使用全局读锁锁定所有表。其命令为:
FLUSH TABLES WITH READ LOCK;
-- 能正常返回结果
select * from t14 limit 1;
-- 报错 Can't execute the query because you have a conflicting read lock;
insert into t14(a,b) values(2,2);
-- 可以使用下面命令解锁
UNLOCK TABLES;
刚才提到的主从延迟问题,好在 mysqldump 包含一个参数 --single-transaction,可以在一个事务中创建一致性快照,然后进行所有表的备份;因此增加这个参数的情况下,备份期间可以进行数据修改。但是需要所有表都是事务引擎表。所以这也是建议使用 InnoDB 存储引擎的原因之一;
二 、表级锁
表级锁有两种:表锁和元数据锁;表锁又分为表读锁和表写锁;
使用场景:事务需要更新某张大表的大部分或全部数据;
表读锁:本线程和其它线程可以读,本线程写会报错,其它线程写会等待
lock tables t14 read;
select * from t14 limit 1;
-- was locked with a READ lock and can't be updated
insert into t14(a,b) values(2,2);
-- 解锁
unlock tables;
表写锁:本线程可以读写,其它线程读写都会阻塞;
lock tables t14 write;
select * from t14 limit 1;
-- was locked with a READ lock and can't be updated
insert into t14(a,b) values(2,2);
-- 解锁
unlock tables;
元数据锁:解决了同一张表上事务和 DDL 并行执行时可能导致数据不一致的问题;
常见问题:
对于开发来说,在工作中应该尽量避免慢查询、尽量保证事务及时提交、避免大事务等;
全局锁会让所有的表变成只读状态,所有更新操作都会被阻塞;
表读锁:本线程和其它线程可以读,本线程写会报错,其它线程写会等待;
表写锁:本线程可以读写,其它线程读写都会阻塞。
MySQL 5.5 之前的默认存储引擎是 MyISAM,5.5 之后改成了 InnoDB最主要的原因就是:
-- InnoDB 支持事务:适合在并发条件下要求数据一致的场景。
-- InnoDB 支持行锁:有效降低由于删除或者更新导致的锁定
两阶段锁协议:
-- 传统的关系型数据库加锁的一个原则是:两阶段锁原则
-- 锁操作分为两个阶段,加锁阶段和解锁阶段,并且保证加锁阶段和解锁阶段不相交
InnoDB 行锁模式:
-- InnoDB 实现了以下两种类型的行锁:共享锁/排他锁(X)
-- 共享锁(S):允许一个事务去读一行,阻止其它事务获得相同数据集的排他锁;
-- 排他锁(X):允许获得排他锁的事务更新数据,阻止其它事务取得相同数据集的共享读锁和排他写锁;
-- 对于普通 select 语句,InnoDB 不会加任何锁;
锁都是悲观锁,乐观锁一般增加一个字段,修改数据前先查询,然后修改数据的时候这个字段会作为一个条件,如果不满足这个条件是不会插入成功的
三、死锁
死锁是指多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象;
1 检测到死锁的循环依赖,立即返回一个错误(这个报错内容请看下面的实验),将参数 innodb_deadlock_detect 设置为 on 表示开启这个逻辑;
2 等查询的时间达到锁等待超时的设定后放弃锁请求。这个超时时间由 innodb_lock_wait_timeout 来控制。默认是 50 秒;InnoDB 中解决死锁问题有两种方式:一般线上业务都建议使用的第 1 种策略;
场景一:同一张表中:不同线程并发访问同一张表的多行数据,未按顺序访问导致死锁
-- 对于多个并发访问同一张表时,如果事先确保每个线程按固定顺序来处理记录,可以降低死锁的概率;
begin;select * from t18 where a=1 for update;select * from t18 where a=2 for update;commit;end;
begin;select * from t18 where a=2 for update;select * from t18 where a=1 for update;commit;end;
场景二: 不同表之间:不同线程并发访问多个表时,未按顺序访问导致死锁
begin;select * from t18 where a=1 for update;select * from t18_1 where a=1 for update;commit;end;
begin;select * from t18_1 where a=1 for update;select * from t18 where a=1 for update;commit;end;
如何降低死锁概率?
--更新 SQL 的 where 条件尽量用索引;
-- 基于 primary 或 unique key 更新数据;
-- 减少范围更新,尤其非主键、非唯一索引上的范围更新;
-- 加锁顺序一致,尽可能一次性锁定所有需要行;
-- 将 RR 隔离级别调整为 RC 隔离级别。
分析死锁的方法?
InnoDB 中,可以使用 SHOW engine INNODB STATUS 命令来查看最后一个死锁的信息;
设置 innodb_print_all_deadlocks = on 可以在 err log 中记录全部死锁信息
内容总结
以上是互联网集市为您收集整理的mysql 锁全部内容,希望文章能够帮你解决mysql 锁所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。