MySQL的行锁、表锁、间隙锁详解(下)

本文涉及的产品
RDS Agent(兼容OpenClaw),2核4GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: MySQL的行锁、表锁、间隙锁详解(下)

4.7 when 使用表锁

对于InnoDB,在绝大部分情况下都应该使用行锁

因为事务,行锁往往是我们选择InnoDB的理由

但在个别特殊事务中,也可以考虑使用表锁


事务需要更新大部分数据,表又较大

若使用默认的行锁,不仅该事务执行效率低(因为需要对较多行加锁,加锁是需要耗时的);

而且可能造成其他事务长时间锁等待和锁冲突;

这种情况下可以考虑使用表锁来提高该事务的执行速度

事务涉及多个表,较复杂,很可能引起死锁,造成大量事务回滚

这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销

当然,应用中这两种事务不能太多,否则,就应该考虑使用MyISAM


在InnoDB下 ,使用表锁要注意


使用LOCK TALBES虽然可以给InnoDB加表锁

表锁不是由InnoDB引擎层管理的,而是由其上一层MySQL Server负责;

仅当autocommit=0、innodb_table_lock=1(默认设置),InnoDB 引擎层才知道MySQL加的表锁,MySQL Server才能感知InnoDB加的行锁;

这种情况下,InnoDB才能自动识别涉及表锁的死锁

否则,InnoDB将无法自动检测并处理这种死锁

在用LOCK TALBES对InnoDB锁时要注意,要将autocommit设为0,否则MySQL不会给表加锁

事务结束前,不要用UNLOCK TALBES释放表锁,因为它会隐式地提交事务

COMMIT或ROLLBACK不能释放用LOCK TALBES加的表锁,必须用UNLOCK TABLES释放表锁,正确的方式见如下语句

需要写表t1并从表t读

image.png

5 死锁

MyISAM表锁是deadlock free的,这是因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁

但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB发生死锁是可能的


发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并退回,另一个事务获得锁,继续完成事务


但在涉及外部锁,或涉及锁的情况下,InnoDB并不能完全自动检测到死锁

这需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决

需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获取所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖垮数据库

我们通过设置合适的锁等待超时阈值,可以避免这种情况发生。

通常来说,死锁都是应用设计的问题,通过调整业务流程、数据库对象设计、事务大小、以及访问数据库的SQL语句,绝大部分都可以避免


下面就通过实例来介绍几种死锁的常用方法。


应用中,不同的程序会并发存取多个表

尽量约定以相同的顺序访问表

程序批处理数据时

事先对数据排序,保证每个线程按固定的顺序来处理记录

在事务中,要更新记录

应直接申请排他锁,而不应该先申请共享锁

在可重复读下,如果两个线程同时对相同条件记录用SELECT...ROR UPDATE加排他写锁

在没有符合该记录情况下,两个线程都会加锁成功

程序发现记录尚不存在,就试图插入一条新记录,如果两个线程都这么做,就会出现死锁

这种情况下,将隔离级别改成READ COMMITTED,就可以避免问题

当隔离级别为READ COMMITED时,如果两个线程都先执行SELECT...FOR UPDATE

判断是否存在符合条件的记录,没有 -> 插入记录;

此时,只有一个线程能插入成功,另一个线程会出现锁等待.

当第1个线程提交后,第2个线程会因主键重出错,但虽然这个线程出错了,却会获得一个排他锁!这时如果有第3个线程又来申请排他锁,也会出现死锁.

对于这种情况,可以直接做插入操作,然后再捕获主键重异常,或者在遇到主键重错误时,总是执行ROLLBACK释放获得的排他锁

如果出现死锁,可以用SHOW INNODB STATUS命令来确定最后一个死锁产生的原因和改进措施。

6 总结

6.1 MyISAM的表锁

共享读锁之间是兼容的,但共享读锁和排他写锁之间,以及排他写锁之间互斥,即读写串行

在一定条件下,MyISAM允许查询/插入并发,可利用这一点来解决应用中对同一表查询/插入的锁争用问题

MyISAM默认的锁调度机制是写优先,这并不一定适合所有应用,用户可以通过设置LOW_PRIPORITY_UPDATES参数或在INSERT、UPDATE、DELETE语句中指定LOW_PRIORITY选项来调节读写锁的争用

由于表锁的锁定粒度大,读写又是串行的,因此如果更新操作较多,MyISAM表可能会出现严重的锁等待,可以考虑采用InnoDB表来减少锁冲突

6.2 对于InnoDB表

  • 行锁基于索引实现
    如果不通过索引访问数据,InnoDB会使用表锁
  • 间隙锁机制及使用间隙锁的原因
  • 不同的隔离级别下,InnoDB的锁机制和一致性读策略不同
  • MySQL的恢复和复制对InnoDB锁机制和一致性读策略也有较大影响
  • 锁冲突甚至死锁很难完全避免

7 索引与锁

在了解InnoDB的锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁

  • 尽量使用较低的隔离级别
  • 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会。

利用索引优化锁


索引可以减少锁定的行数

索引可以加快处理速度,同时也加快了锁的释放

选择合理的事务大小,小事务发生锁冲突的几率也更小

给记录集显式加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。

不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大减少死锁的机会。

尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。

不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁。

对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能

索引的维护和优化

删除重复和冗余的索引

primary key(id) ,unique key (id) ,index(id)

主键索引、唯一索引、单列索引

  • 注意加粗的联合索引
    Index(a),index(a,b)
    primary key(id),index(a,id)
  • 删除重复和冗余的索引
  • image.png
  • 查找未被使用过的索引
  • image.png
  • 更新索引统计信息及减少索引碎片

analyze table table_ name

optimize table table_ name

使用不当会导致锁表


参考

https://www.cnblogs.com/chenqionghe/p/4845693.html

https://developer.aliyun.com/article/3780


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
12月前
|
SQL AliSQL 关系型数据库
MYSQL的全局锁和表锁
本文介绍了MySQL中的锁机制,包括全局锁、表级锁及其应用场景。全局锁通过`Flush tables with read lock (FTWRL)`实现,主要用于全库逻辑备份,但会阻塞更新和结构变更操作。表级锁分为显式表锁(`lock tables`)和元数据锁(MDL),前者用于控制并发访问,后者自动加锁以确保读写正确性。文章还探讨了如何安全地为小表添加字段,建议通过设置DDL等待时间或使用MariaDB/AliSQL的NOWAIT/WAIT功能避免业务阻塞。这些方法有助于在高并发场景下优化数据库性能与安全性。
312 0
|
12月前
|
SQL 存储 关系型数据库
滴滴面试:明明 mysql 加的是 行锁,怎么就变 表锁 了?
滴滴面试:明明 mysql 加的是 行锁,怎么就变 表锁 了?
|
关系型数据库 MySQL 网络安全
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
501 25
|
存储 关系型数据库 MySQL
MySQL进阶突击系列(06)MySQL有几种锁?| 别背答案,现场演示一下
本文详细解析了MySQL InnoDB存储引擎的锁机制,涵盖读锁、写锁、意向锁、记录锁、间隙锁和临键锁等8种锁类型。重点探讨了不同锁类型的加锁与释放方式,以及事务并发场景下的实战验证。通过具体示例,展示了在不同情况下锁的行为及其对事务的影响。文章还特别强调了锁的作用范围主要是索引,并解释了锁如何影响数据的读写操作。最后总结了并发事务中加锁规则,帮助读者深入理解MySQL的锁机制。
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
828 1
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
455 0
|
8月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
524 158
|
8月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
8月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1367 152
|
8月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
991 156

推荐镜像

更多