MySQL-锁

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 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
相关文章
|
19天前
|
SQL 关系型数据库 MySQL
MySQL数据库进阶第五篇(锁)
MySQL数据库进阶第五篇(锁)
|
24天前
|
存储 SQL 关系型数据库
MYSQL--锁机制*
MYSQL--锁机制*
|
2月前
|
关系型数据库 MySQL 数据库
MySQL的行级锁锁的到底是什么?
本文简述了InnoDB的行级锁机制,包括记录锁、间隙锁和Next-Key锁。记录锁锁定索引记录,防止其他事务对相同值的行进行操作;间隙锁锁定索引记录间的间隙,防止插入。Next-Key锁是两者的结合,锁定记录及其前后间隙。在可重复读(RR)隔离级别下,加锁策略涉及Next-Key锁,但会因查询条件退化为行锁或间隙锁。MySQL的加锁机制遵循两个原则和两个优化,例如唯一索引等值查询时退化为行锁。RR级别虽能防止幻读,但也可能降低并发并引发死锁,因此有些场景下会选择读已提交(RC)级别。
MySQL的行级锁锁的到底是什么?
|
23天前
|
存储 SQL 关系型数据库
【MySQL技术内幕】6.3-InnoDB中的锁
【MySQL技术内幕】6.3-InnoDB中的锁
153 57
|
13天前
|
存储 关系型数据库 MySQL
深入浅出MySQL事务管理与锁机制
MySQL事务确保数据一致性,ACID特性包括原子性、一致性、隔离性和持久性。InnoDB引擎支持行锁、间隙锁和临键锁,提供四种隔离级别。通过示例展示了如何开启事务、设置隔离级别以及避免死锁。理解这些机制对优化并发性能和避免数据异常至关重要。【6月更文挑战第22天】
94 3
|
24天前
|
存储 关系型数据库 MySQL
深入研究MySQL意向锁
MySQL意向锁是一种特殊的表级锁,由InnoDB存储引擎在操作数据之前自动添加,无需用户干预。它分为意向共享锁(IS)和意向排他锁(IX)两种。意向锁的主要作用是协调行锁和表锁的关系,优化加锁策略,避免全表扫描判断是否存在行锁。意向锁之间不会冲突,但会与表级别的排他锁冲突,从而确保数据库并发访问的一致性和完整性。简而言之,意向锁提高了数据库并发操作的性能和效率。
150 5
|
23天前
|
存储 SQL 关系型数据库
【MySQL技术内幕】6.5-锁问题、阻塞、死锁、锁升级
【MySQL技术内幕】6.5-锁问题、阻塞、死锁、锁升级
47 2
|
23天前
|
SQL 存储 算法
【MySQL技术内幕】6.4-锁的算法
【MySQL技术内幕】6.4-锁的算法
27 1
|
11天前
|
SQL 存储 关系型数据库
Mysql-事务-锁-索引-sql优化-隔离级别
Mysql-事务-锁-索引-sql优化-隔离级别
|
16天前
|
SQL NoSQL 关系型数据库
Mysql锁及适用场景
Mysql锁及适用场景
28 0