【MySQL 流浪之旅】 第六讲 浅谈 MySQL 锁

2024-01-30 18:04

本文主要是介绍【MySQL 流浪之旅】 第六讲 浅谈 MySQL 锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

系列文章目录

【MySQL 流浪之旅】 第一讲 MySQL 安装
【MySQL 流浪之旅】 第二讲 MySQL 基础操作
【MySQL 流浪之旅】 第三讲 MySQL 基本工具
【MySQL 流浪之旅】 第四讲 MySQL 逻辑备份
【MySQL 流浪之旅】 第五讲 数据库设计的三个范式


目录

系列文章目录

一、什么是锁?

二、锁的类型?

三、锁的算法?

四、锁与事务隔离级别

4.1. 隔离级别简介

4.2. Read Uncommitted(读取未提交内容)

4.3. Read Committed(读取提交内容) 

4.4. Repeatable Read(可重读)

4.5. Serializable(可串行化)

五、死锁


一、什么是锁?

锁是实现事务隔离性最广泛使用的技术。以 MySQL InnoDB 为例,数据库的锁有排他锁,共享锁,意向锁,自增锁,间隙锁。

按照粒度分为锁定整个表的表级锁(table-level locking)和锁定数据行的行级锁(row-level locking):

  • 表级锁具有开销小、加锁快的特性;但是表级锁的锁定粒度较大,发生锁冲突的概率高,支持的并发度低;
  • 行级锁具有开销大,加锁慢的特性;但是行级锁的锁定粒度较小,发生锁冲突的概率低,支持的并发度高。

InnoDB 存储引擎同时支持行级锁(row-level locking)和表级锁(table-level locking),默认情况下采用行级锁。
InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。所以如果访问没有命中索引,就无法使用行锁,将要退化为表锁(共享行锁上升为共享表锁,排他行锁上升为排他表锁)。

二、锁的类型?

InnoDB存储引擎实现的是行级锁

  • 共享锁(S Lock):允许事务读一行数据
  • 排他锁(X Lock):允许事务删除或更新一行数据

排他锁和共享锁的兼容性

 

  • 意向共享锁(IS Lock):事务想要获得一张表中某几行的共享锁
  • 意向排他锁(IX Lock):事务想要获得一张表中某几行的排他锁

 意向排他锁和意向共享锁的兼容性

  • 间隙锁:where条件是一个范围时,数据库会锁定区间数据,主要是解决幻读问题。 
  • 自增锁:自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。控制同一sql 语句插入的所有记录的自增id是连续的。

平时还有提到的悲观锁,乐观锁,在数据库层面上没有这个锁的概念,如果要做简单映射,悲观锁可以映射成排他锁,乐观锁是由应用层面保障的,和 DB 的锁概念无关。

  • 乐观锁:认为冲突概率低,操作数据时,不会锁定数据,只有在提交修改时,才检查。如果数据已被修改,则回滚,否则提交。 
  • 悲观锁:一种并发控制方法。认为冲突概率高,每次读写前都加锁。

所以我们说,锁的分类从不同角度来看有不同的类型:

三、锁的算法?

  • Record Lock:单个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范围,但不包含基本本身
  • Next-key Lock:Gap Lock + Record Lock:锁定一个范围,并且锁定记录本身 

四、锁与事务隔离级别

4.1. 隔离级别简介

事务的隔离级别是用来描述并发控制机制中不同事务之间隔离程度的参数。以下是几种常见的隔离级别及其特点:

  • Read Uncommitted(读取未提交内容)
  • Read Committed(读取提交内容)
  • Repeatable Read(可重读)
  • Serializable(可串行化)
事务隔离级别脏读不可重复读幻读
Read Uncommitted(读取未提交内容)
Read Committed(读取提交内容)
Repeatable Read(可重读)
Serializable(可串行化)

4.2. Read Uncommitted(读取未提交内容)

定义:所有事务都可以看到其他未提交事务的执行结果。(本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少)读取未提交的内容也称为脏读,所以在该隔离级别下是存在脏读这种缺陷的。在该隔离级别是允许脏读。

锁的状态:Read Uncommitted这个隔离级别是不加锁的,所有的事物都能任意操作数据,数据是没有任何一致性可言,其实数据就是处于混乱的状态中。

图示

图中所示,会导致什么问题呢?

tab2在B时刻查询到了表的数据,但是如果在C时刻发生了回滚,那么tab1的数据的插入不成功的,其实这时表里是没有数据的,但是事务tab2却查询到了数据,这就导致数据不一致了。

4.3. Read Committed(读取提交内容) 

定义:只能读取到已经提交的数据,这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 会出现所谓的不可重复读(Nonrepeatable Read)这种缺陷,因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

锁的状态:该隔离级别下,数据的读取都是不加锁的,但是事务的写入、修改、删除是加锁的。

4.4. Repeatable Read(可重读)

定义:这是MySQL的默认事务隔离级别,他确保一事务的多个会话在并发读取数据时,会看到同样的数据行。

T1

T2

T3

begin;

begin;

begin;

root@localhost> select id,class_name,teacher_id from class_teacher;

+----+--------------+------------+

| id | class_name   | teacher_id |

+----+--------------+------------+

|  1 | 初三一班     |          1|

|  2 | 初三二班     |         1 |

+----+--------------+------------+

2 rows in set (0.00 sec)

update class_teacher set class_name='初三三班' where id=1;

Waiting……

root@localhost> select id,class_name,teacher_id from class_teacher;

+----+--------------+------------+

| id | class_name   | teacher_id |

+----+--------------+------------+

|  1 | 初三一班     |          1|

|  2| 初三二班     |         1 |

+----+--------------+------------+

2 rows in set (0.00 sec)

insert into class_teacher values (null,'初三三班',1);

commit;

root@localhost> select id,class_name,teacher_id from class_teacher;

+----+--------------+------------+

| id | class_name   | teacher_id |

+----+--------------+------------+

|  1 | 初三一班     |          1|

|  2 | 初三二班     |         1 |

|  3 | 初三三班     |         1 |

+----+--------------+------------+

3 rows in set (0.00 sec)

从上图可以看出,传统的Repeatable Read(可重读),为了保证可重读,读取出来的数据行是加锁的,所以这些行在commit(锁释放)前是不能修改的,但是他不会对新插入的行加锁,所以T3是可以插入数据的,并且再次查询的时候就会看到新插入的的行,这种现象就是幻读。

4.5. Serializable(可串行化)

定义:这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁(每次读都需要获得表级共享锁)。在这个级别,可能导致大量的超时现象和锁竞争,读写相互都会阻塞。因此,会导致大量的超时现象。

锁的状态:MySQL从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。

五、死锁

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。

show engine innodb status查看死锁信息

死锁通常包括以下四个必要条件:

  1. 互斥条件(Mutual Exclusion):每个资源只能同时被一个线程占用。如果一个线程占用了某个资源,其他线程就无法同时占用它。
  2. 请求与保持条件(Hold and Wait):线程在持有某些资源的同时,又请求其他资源。如果线程在等待其他资源时不释放已占用的资源,就可能导致死锁。
  3. 不可剥夺条件(No Preemption):系统不能抢占线程占用的资源,只能由线程自愿释放。
  4. 循环等待条件(Circular Wait):多个线程之间形成一个环形等待其他线程释放资源的情况。 

为了预防和解决死锁问题,可以采取以下策略:

  1. 加强互斥条件:尽量减少共享资源的互斥性,或者使用更高级的同步机制来替代基本的互斥锁。
  2. 加强请求与保持条件:要求数资源时,尽量一次性请求所有需要的资源,而不是逐个请求。
  3. 加强不可剥夺条件:允许操作系统抢占线程占用的资源,以避免某些线程长时间占用资源而导致死锁。
  4. 加强循环等待条件:引入资源分配图,检测潜在的死锁情况,然后采取措施来打破等待环路。
  5. 使用超时:线程在等待资源时,设置一个超时时间,超时后可以放弃等待或者重试。
  6. 使用死锁检测和恢复机制:系统可以定期检测死锁,并采取措施来解除死锁,如终止某些线程或回滚操作。

这篇关于【MySQL 流浪之旅】 第六讲 浅谈 MySQL 锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/661087

相关文章

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

MySQL错误代码2058和2059的解决办法

《MySQL错误代码2058和2059的解决办法》:本文主要介绍MySQL错误代码2058和2059的解决办法,2058和2059的错误码核心都是你用的客户端工具和mysql版本的密码插件不匹配,... 目录1. 前置理解2.报错现象3.解决办法(敲重点!!!)1. php前置理解2058和2059的错误

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

MySQL Workbench 安装教程(保姆级)

《MySQLWorkbench安装教程(保姆级)》MySQLWorkbench是一款强大的数据库设计和管理工具,本文主要介绍了MySQLWorkbench安装教程,文中通过图文介绍的非常详细,对大... 目录前言:详细步骤:一、检查安装的数据库版本二、在官网下载对应的mysql Workbench版本,要是

mysql数据库重置表主键id的实现

《mysql数据库重置表主键id的实现》在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,本文主要介绍了mysql数据库重置表主键id的实现,具有一定的参考价值,感兴趣的可以了... 目录关键语法演示案例在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,当我们

浅谈mysql的sql_mode可能会限制你的查询

《浅谈mysql的sql_mode可能会限制你的查询》本文主要介绍了浅谈mysql的sql_mode可能会限制你的查询,这个问题主要说明的是,我们写的sql查询语句违背了聚合函数groupby的规则... 目录场景:问题描述原因分析:解决方案:第一种:修改后,只有当前生效,若是mysql服务重启,就会失效;

MySQL多列IN查询的实现

《MySQL多列IN查询的实现》多列IN查询是一种强大的筛选工具,它允许通过多字段组合快速过滤数据,本文主要介绍了MySQL多列IN查询的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析与优化1.

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作