MySQL-锁

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

概念

锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具,在计算机中,是协调多个进程或线程并发访问某一资源的一种机制,在数据库当中,除了传统的计算资源(CPU、RAM、I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源,如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素

举例

在购买商品时, 商品库存只有 1 个时,两个人同时买时, 谁买到的问题,会用到事务, 先从库存表中取出物品的数据, 然后插入订单,付款后,插入付款表信息,更新商品的数量, 在这个过程中, 使用锁可以对有限的资源进行保护,解决隔离和并发的矛盾

锁分类

按操作分

  • 读锁(共享锁):针对同一份数据,多个读取操作可以同时进行而不互相影响
  • 写锁(排它锁):当前写操作没有完成前,会阻断其他写锁和读锁

按粒度分

  • 表锁
  • 行锁
  • 页锁

表锁

偏向 MYISAM 存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最底,整张表就只能一个人使用

示例

1.建立一张Myisam引擎的表

CREATE TABLE `locktest` (
  `id` INT (11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR (255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE = MyISAM AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8;

2.查看表有没有被锁过

SHOW OPEN TABLES;

3.对表加锁

LOCK TABLE locktest READ,
 locktest2 WRITE;

4.对表进行解锁

UNLOCK TABLES

读写锁对操作和性能产生哪些影响

1.对 locktest 添加读锁 lock table locktest read;(共享)

当前连接

是否可以查看自己 可以
是否可以更新 不可以
能不能读别的表 不可以,当前表还没有解锁,不能放下当前, 操作别的内容

另一个连接

是否可以查看 可以
是否可以更新 当更新时,处理阻塞状态,等待解锁后,才能进行更新
能不能读别的表 可以

2.对 locktest 添加写锁 lock table locktest write;(排它)

当前连接

能否读自己锁过的表 可以
能否改自己锁过的表 可以
能否读取别的表 不可以

另一个连接

能否没有加过锁的表 可以
能否对被锁过的表进行操作 阻塞,等待解锁时,能查到

表锁分析

SHOW STATUS LIKE 'table%';
  • Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数
  • Table_locks_waited:出现表级锁定争用而发生等待的次数

Myisam 的读写锁调度是写优,这也是 myisam 不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量更新会使用查询很难得到锁,从而造成永久阻塞

淘宝

买家库,偏向读取

卖家库,更多偏向写

行锁

偏向 InnoDB 存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最底,并发度也最高,InnoDB 与 MyISAM 的最大不同点:一是支持事务,二是采用了行级锁

事务

ACID属性

  • 原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
  • 一致性(Consistency)一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。让数据保持一定上的合理,一个商品出库时,仓库商品数量减 1,对应用户的购物车中商品加 1。
  • 隔离性(Isolation)隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 持久性(Durability)持久性是指一个事务一旦被提交了,就不能再回滚了,已经把数据保存到数据库当中了。

并发事务处理带来的问题

更新丢失:两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其它事务的存在,就会发生丢失更新问题,最后的更新覆盖了其它事务所做的更新

脏读:老板要给程序员发工资,程序员的工资是 3.6 万/月。但是发工资时老板不小心按错了数字,按成 3.9 万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了 3 千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成 3.6 万再提交,实际程序员这个月的工资还是 3.6 万,但是程序员看到的是 3.9 万。他看到的是老板还没提交事务时的数据。这就是脏读。事务 A 读到了事务 B 已修改,但尚未提交的数据

解决办法,Read committed!读提交,能解决脏读问题

不可重复读:程序员拿着工资卡(卡里当然是只有 3.6 万),当他买单时(程序员事务开启),收费系统事先检测到他的卡里有 3.6 万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了。程序员就会很郁闷,明明卡里是有钱的…,一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读,事务 A 读取到了事务 B 已经提交的修改数据

解决办法,Repeatable read

重复读:程序员拿着工资卡(卡里还是有 3.6 万),当他买时(事务开启,不允许其他事务的 UPDATE 修改操作),收费系统事先检测到他的卡里有 3.6 万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

幻读:程序员某一天去消费,花了 2 千元,然后他的妻子去查看他今天的消费记录(妻子事务开启),看到确实是花了 2 千元,就在这个时候,程序员花了 1 万买了一部电脑,即新增 INSERT 了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了 1.2 万元,似乎出现了幻觉,这就是幻读。

解决办法,Serializable 但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

对应关系

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

事务隔离级别

  • Read uncommitted:就是一个事务可以读取另一个未提交事务的数据
  • Read committed:一个事务要等另一个事务提交后才能读取数据
  • Repeatable read:就是在开始读取数据(事务开启)时,不再允许修改操作
  • Serializable:在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读

查看隔离级别

SELECT @@GLOBAL .transaction_isolation ,@@transaction_isolation;

设置隔离级别

  • 全局的
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • 当前会话
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

示例

  • 演示行锁

5.5 以后,默认后,事务会自动提交,由于演示,开两个连接都关闭自动提交

SET autocommit = 0;

做以下操作,执行更新操作,自己可以查看到更新的内容,连接 2 看不到更新的内容,只有 commit 后,才能看到更新的内容,连接 1 执行更新操作,连接 2 也执行更新操作,更新同一条记录,连接 1 没有提交事务时,连接 2 更新处于阻塞状态,当 commit 时,连接 2 才会继续执行,连接 2 更新也要 commit,连接 1 和连接 2 同时更新数据,但更新的不是同一条记录,不会影响

索引失效行锁变表锁

使用 varchar 类型时,没有添加引号,导致索引失效,就会造成行锁变表锁,另一个连接更新数据时,会造成阻塞

间隙锁

当我们使用范围条件,而不是相等条件检索数据,并请求共享或排它锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁,对于键值在条件范围内但并不存在的记录叫做 间隙,InnoDB 也会对这个 间隙 加锁,这种锁机制,就是所谓的间隙锁

如何锁定一行数据

在查询之后添加 for update,其它操作会被阻塞,直到锁定的行提交 commit

SHOW STATUS LIKE 'innodb_row_lock%';

悲观锁

就是很悲观,它对于数据被外界修改持保守态度,认为数据随时会修改,所以整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系数据库提供的锁机制,事实上关系数据库中的行锁,表锁不论是读写锁都是悲观锁

乐观锁

顾名思义,就是很乐观,每次自己操作数据的时候认为没有人回来修改它,所以不去加锁,但是在更新的时候会去判断在此期间数据有没有被修改,需要用户自己去实现,不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性

为什么要使用乐观锁呢?

对于读操作远多于写操作的时候,大多数都是读取,这时候一个更新操作加锁会阻塞所有读取,降低了吞吐量。最后还要释放锁,锁是需要一些开销的,我们只要想办法解决极少量的更新操作的同步问题。换句话说,如果是读写比例差距不是非常大或者你的系统没有响应不及时,吞吐量瓶颈问题,那就不要去使用乐观锁,它增加了复杂度,也带来了额外的风险。

乐观锁的实现方式

版本号

就是给数据增加一个版本标识,在数据库上就是表中增加一个 version 字段,每次更新把这个字段加 1,读取数据的时候把 version 读出来,更新的时候比较 version,如果还是开始读取的 version 就可以更新了,如果现在的 version 比老的version 大,说明有其他事务更新了该数据,并增加了版本号,这时候得到一个无法更新的通知,用户自行根据这个通知来决定怎么处理,比如重新开始一遍。

时间戳

和版本号基本一样,只是通过时间戳来判断而已,注意时间戳要使用数据库服务器的时间戳不能是业务系统的时间,同样是在需要乐观锁控制的 table 中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的 version 类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 锁
MySQL里常见的几种锁
57 3
|
2月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
118 1
|
2月前
|
关系型数据库 MySQL Java
MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
236 2
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
92 1
|
3月前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
344 5
|
2月前
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
83 0
|
2月前
|
关系型数据库 MySQL 数据库
mysql锁详解
通过理解并合理运用MySQL中的锁机制,开发者可以有效管理数据库并发访问,平衡性能与数据一致性需求。更多关于MySQL锁的深入探讨和最佳实践,请参考专业的数据库管理资源[[深入MySQL锁机制详解
60 0
|
3月前
|
关系型数据库 MySQL 数据库
Mysql的锁
本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
|
3月前
|
存储 SQL 关系型数据库
MySQL 的锁机制,那么多的锁,该怎么区分?
MySQL 的锁机制,那么多的锁,该怎么区分?
50 0
|
4月前
|
监控 关系型数据库 MySQL
在Linux中,mysql的innodb如何定位锁问题?
在Linux中,mysql的innodb如何定位锁问题?