【MySQL】数据库管理过程中的锁问题

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 【MySQL】数据库管理过程中的锁问题

按照锁的大小,我们分为全局锁,表锁,页锁,和行锁。

不同级别的锁有不同的作用,这里我简单列出我在工作过程中对这些锁的理解。

什么使用用全局锁?

全局锁是用来对整个数据库加锁的锁。

我们可以使用Flush Table With Read Lock(FTWRL)来让数据库进入只读状态。

使用这个命令之后,其他线程的如下操作会被阻塞:DML数据增删改操作,DDL数据定义操作,如建表,修改表结构等操作以及更新类事务的提交语句。

全局锁的使用场景在我们公司为:重要库的一天一次的全量备份,次要库的一周一次的全量备份。

做全库的逻辑备份,我们就需要保证再这段时间内没有新的数据,保证数据库只读,否则就会出现数据异常问题,之后恢复数据也会出现问题。

虽然说全局锁肯定也不太好,毕竟使用了全局锁就意味着主库备份时肯定不能写入修改数据了,而从库备份时也就不能同步主库过来的binlog日志,都会有些影响。

但是如果不加全局锁,再备份期间就会导致一些修改操作,而备份恢复的时候这些修改操作已经执行,从而导致的一些数据异常问题,所以加锁能帮助我们避免这些问题。

其实这也就是所谓的数据一致性问题而已,我们在备份的时候,如果可以记录对这些备份数据的修改,并且我们备份数据的时候,能先拿到一下这些数据的快照,那么似乎就可以解决这些数据不一致的问题了,所以就有了mysql自带的备份工具mysqldump。

当 mysqldump 使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC 的支持,这个过程中数据是可以正常更新的。但是对于 MyISAM这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用FTWRL命令了。所以,single-transaction方法只适用于所有的表使用事务引擎的库。如果有的表使用了不支持事务的引擎,那么备份就只能通过FTWRL 方法。

补充:内容来自《MySQL45讲》

为什么不使用 set global readonly=true 的方式呢?

readonly 方式也可以让全库进入只读状态,但我还是会建议你用 FTWRL 方式,主要有两个原因:

一是,在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,我不建议你使用。

二是,在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)。不论是哪种方法,一个库被全局锁上以后,你要对里面任何一个表做加字段操作,都是会被锁住的。

什么时候用表锁?

对于MyISAM这种不支持行锁的存储引擎,我们需要锁数据的时候就只能以表为单位来进行加锁,比如使用lock table xxx read/write的方式,并且使用unlock tables的方式来释放锁。

表锁的加锁消耗相比于行锁更小,但是由于锁的粒度比较大,因此容易导致并发问题。

当我们在某个线程使用lock table xxx 的方式来对一张表加上读锁的时候,其他线程只能读取当前这张表,如果写那么会阻塞,也就是我们所谓的读读不互斥,读写互斥。

而如果我们对一张表加了写锁,那么其他线程读取这张表的时候就会直接阻塞,可想而知,死锁的发生概率非常的大。

还要注意的一个锁是MDL元数据锁,这个锁不需要显式的调用,它的作用是帮助我们再执行操作的时候保证表结构不被修改。

同样的,我们在读(包括增删改查)取一个表的时候,会得到MDL读锁,读锁之间不互斥。

但是如果我们开始使用alter语句去修改表结构,那么我们必须确保能拿到MDL写锁,而写锁的获取需要保证前面没有读锁,否则前面有读锁时,写锁需要先阻塞,而此时写锁阻塞,再当前alter语句之后的所有语句,包括获取MDL读锁的语句也会进行阻塞,那么此时就又会出现死锁了。

所以我们一般再要进行alter语句的时候我们会设一个超时时间。

什么时候用行锁?

MySQL InnoDB 存储引擎的行锁是基于索引的。当执行一个含有 WHERE 条件的 SQL 查询时,InnoDB 存储引擎会根据相应的索引定位到符合条件的记录,并对这些记录加上行锁。

行锁的粒度是以记录为单位的,只有在命中对应的索引之后,才会对符合条件的记录进行行锁加锁。这种方式可以提高并发性能,因为只有真正需要锁定的记录才会被锁定,而不是对整个表或整个索引进行锁定。

需要注意的是,如果查询没有命中索引,而是使用全表扫描的方式进行,那么会出现全表锁(Table Lock),而不是行锁。全表锁会锁定整个表,对于并发性能会有一定的影响。因此,在设计数据库表和索引时,合理选择和创建合适的索引是非常重要的。

并且行锁的使用遵循两阶段锁原则,上面我也提到了,只有用到了某条记录才会对某条记录加锁,而如果两个事务都需要对同一个行锁进行修改,那么后来者需要等待先来者事务提交之后才会结束阻塞,否则需要等待事务提交。

也正是这个原因,我们应该需要确保最有可能导致阻塞的语句,放在最接近事务结束的地方,我们公司有一个SKU系统,我们会确保对SKU的操作一定是放在最后进行的,也就是一般情况都是我们的save/update语句的下一条语句就是return,确保对其他事务的影响最小。

随着上面的情况,如果我们的事务一修改了记录1,然后事务二修改了记录2,而之后当事务一需要操作记录2的时候,事务二需要操作记录1的时候就会出现死锁。

对于这种死锁,我们的计划是设定锁超时自动释放,参数为innodb_lock_wait_timeout,由于我们是下游,我们的上游接口有一定的时间,所以我们设定这个参数为10s左右。

mysql害提供了一个innodb_deadlock_detect,他会自动进行死锁检测,但是因为死锁检测的性能消耗是很高的。毕竟他需要扫描每一个事务对应的线程有没有被其他线程锁住,这很消耗性能。

所以我们编码的时候一般需要保证尽可能多的测试,确保业务尽可能不出现死锁,也就是从源头上减少出现死锁的可能性。

同时当初还考虑到由于死锁是出现在对同一行记录的操作,所以我们有的时候会把一条记录进行拆分,合并之后才是这条完整的记录,我们可以吧一些操作先操作在其他行上,或者说我们也会创建中间表,然后再一定时间之后合并操作。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
20 4
|
4天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
13 1
|
13天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
69 1
|
15天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
59 2
|
18天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
74 4
|
1天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
16 0
|
24天前
|
存储 关系型数据库 MySQL
如何在MySQL中创建数据库?
【10月更文挑战第16天】如何在MySQL中创建数据库?
|
14天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
45 0
|
23天前
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
104 0
|
23天前
|
存储 SQL 关系型数据库
MySQL Workbench支持哪些数据库引擎
【10月更文挑战第17天】MySQL Workbench支持哪些数据库引擎
17 0