百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

mysql专题 - 锁机制 mysql锁机制解析

bigegpt 2024-10-21 03:46 2 浏览

mysql专题 - 锁机制

无论是工作还是面试我们都有很多可能性接触mysql。我打算好好梳理一下Mysql的基础,因此打算开启一个专题。有不对的地方也麻烦指正。


mysql锁进行划分

  • 按照锁的粒度划分:行锁、表锁、页锁
  • 两种思想上的锁:悲观锁、乐观锁。
  • InnoDB中有几种行级锁类型:Record Lock、Gap Lock、Next-key LockRecord Lock:在索引记录上加锁Gap Lock:间隙锁Next-key Lock:Record Lock+Gap Lock

行锁

行级锁是颗粒度最细的一种锁,表示对当前操作的行进行加锁。能减少数据操作的冲突,但是加锁开销最大,有可能会出现死锁。行级锁按照使用方式分为共享锁和排他锁。

  • 共享锁(读锁 S锁)事务A对表 T的某一行R进行了(以下简称TR) S锁操作,这个时候其他事务只能对 TR加S锁不能加X锁(X锁在下面)。这保证了其他事务可以读,但在A释放TR上的S锁之前不能对TR做任何修改。-- 加 S 锁示例
    SELECT * FROM tmp_table WHERE id = '3' LOCK IN SHARE MODE;
  • 排它锁(写锁 X锁)事务A对表 TR 做了X锁操作,这个时候其他事务不能对 TR加锁。这保证了其他事务在A释放TR上的锁之前不能再读取和修改TR。排它锁也成为独占锁-- 加 X 锁
    SELECT * FROM tmp_table WHERE id = '3' for update;

行级锁是如何引起死锁的呢?

单表操作的时候是不会引起死锁的,当存在多表关联的时候就有可能产生死锁。

-- 伪代码,

-- 事务1开始
select * from tmp_table where id = '1' for update;
select * from tmpA a,tmp_table2 b where a.name = b.name;
-- 事务1结束

-- 事务2开始
select * from tmp_table2 where id = '1' for update;
select * from tmpA a,tmp_table1 b where a.name = b.name;
-- 事务2结束

表锁

表级锁是mysql锁中粒度最大的一种锁,表示当前的操作对整张表加锁。这种锁开销小,不会死锁,但是很容易发生数据操作的冲突。大部分的mysql引擎都支持。MyISAM和InnoDB都支持表级锁,InnoDB默认的是行级锁。

同样的表锁也分为共享锁和排他锁

--  共享锁 读锁
LOCK TABLE tmp_table READ;
-- 排它锁 写锁
LOCK TABLE tmp_table WRITE;
-- 解锁
unlock tables;

页锁

页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多。一次锁定相邻的一组记录。BDB支持页级锁。目前我工作中很少是哟个 BDB引擎,因此这部分就不看如何加的了,了解个大概就可以

乐观锁和悲观锁

首先客观所和悲观锁并仅仅是数据库的概念,很多地方都会有这种概念。

悲观锁总是把事情想的悲观,在处理数据的时候会认为其他事务会处理自己要处理的数据,就有可能产生错误。为了防止这种情况发生,因此悲观锁在处理数据的时候都是先加锁,加锁成功后在处理自己要处理的事务

乐观锁则相反,在处理数据的时候乐观的认为不会有其他事务来处理数据,因此先进行数据处理,在最终提交数据的时候检查数据是否冲突。

从上面的解释来看

  • 悲观锁效率较低(因此持有锁的时间比较长),而且也可能产生死锁,降低了并发量,但是保证了数据的准确性
  • 乐观锁不会产生死锁,相对效率也较高,但是有可能会产生脏数据

看下mysql中如何模拟悲观锁

-- 取消mysql事务自动提交
set autocommit=0;
-- 开始事务 (三者选一就可以)
begin;/begin work;/start transaction;
-- 加锁操作及事务操作
select ... for update;
-- 提交事务
commit;/commit work;


-- 窗口1
set autocommit=0;
-- 锁表
select * from tmp_table for update;


-- 窗口2:
-- 会显示等待状态,一直到窗口1执行commit提交事务才会出现下面的显示结果
update tmp_table set tmp6='3' WHERE id = '3' ;

InnoDB中的锁

InnoDB锁的特性

  • 在不通过索引条件查询的时候,InnoDB使用的是表锁
  • MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行 的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
  • 表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论 是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。
  • 即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同 执行计划的代价来决定的,如果 MySQL 认为全表扫 效率更高,比如对一些很小的表,它 就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。

Record Lock

单条索引上加锁,record lock 永远锁的是索引,而非数据本身,如果innodb表中没有索引,那么会自动创建一个隐藏的聚集索引,锁住的就是这个聚集索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个类似于表锁,但原理上和表锁应该是完全不同的。

Gap Lock

间隙锁,是在索引的间隙之间加上锁,这是为什么Repeatable Read隔离级别下能防止幻读的主要原因。

ps:幻读指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围内的记录时,会产生幻行。

接用网上的例子

mysql> select * from product_copy;
+----+--------+-------+-----+
| id | name   | price | num |
+----+--------+-------+-----+
|  1 | 伊利   |    68 |   1 |
|  2 | 蒙牛   |    88 |   1 |
|  6 | tom    |  2788 |   3 |
| 10 | 优衣库 |   488 |   4 |
+----+--------+-------+-----+
其中id为主键 num为普通索引
窗口A:
mysql> select * from product_copy where num=3 for update;
+----+------+-------+-----+
| id | name | price | num |
+----+------+-------+-----+
|  6 | tom  |  2788 |   3 |
+----+------+-------+-----+
1 row in set

窗口B:
mysql> insert into product_copy values(5,'kris',1888,2);
这里会等待  直到窗口A commit才会显示下面结果
Query OK, 1 row affected

但是下面是不需要等待的
mysql> update product_copy set price=price+100 where num=1;
Query OK, 2 rows affected
Rows matched: 2  Changed: 2  Warnings: 0
mysql> insert into product_copy values(5,'kris',1888,5);
Query OK, 1 row affected

我们要关注的是索引字段num。通过上面的例子可以发现 num=2是被锁住的,而操作 num = 1 或者 5的都能正常使用。

即锁的作用是在1,3的间隙之间加上了锁。因此就防止了幻读的产生



相关推荐

C#广义表(广义表headtail)

在C#中,广义表(GeneralizedList)是一种特殊的数据结构,它是线性表的推广。广义表可以包含单个元素(称为原子),也可以包含另一个广义表(称为子表)。以下是一个简单的C#广义表示例代...

「C#.NET 拾遗补漏」04:你必须知道的反射

阅读本文大概需要3分钟。通常,反射用于动态获取对象的类型、属性和方法等信息。今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的。获取类型的成员Type类的GetMembe...

C#启动外部程序的问题(c#怎么启动)

IT&OT的深度融合是智能制造的基石。本公众号将聚焦于PLC编程与上位机开发。除理论知识外,也会结合我们团队在开发过程中遇到的具体问题介绍一些项目经验。在使用C#开发上位机时,有时会需要启动外部的一些...

全网最狠C#面试拷问:这20道题没答出来,别说你懂.NET!

在竞争激烈的C#开发岗位求职过程中,面试是必经的一道关卡。而一场高质量的面试,不仅能筛选出真正掌握C#和.NET技术精髓的人才,也能让求职者对自身技术水平有更清晰的认知。今天,就为大家精心准备了20道...

C#匿名方法(c#匿名方法与匿名类)

C#中的匿名方法是一种没有名称只有主体的方法,它提供了一种传递代码块作为委托参数的技术。以下是关于C#匿名方法的一些重要特点和用法:特点省略参数列表:使用匿名方法可省略参数列表,这意味着匿名方法...

C# Windows窗体(.Net Framework)知识总结

Windows窗体可大致分为Form窗体和MDI窗体,Form窗体没什么好细说的,知识点总结都在思维导图里面了,下文将围绕MDI窗体来讲述。MDI(MultipleDocumentInterfac...

C#语言学习笔记19 —— C# 程序的结构,已做开发多年,还未认真看过

C#程序的结构C#程序由一个或多个文件(.cs文件)组成。每个文件包含0个或多个命名空间。命名空间包含类、结构、接口、枚举、委托等类型或其他命名空间。在写本笔记时(2025年5月),.Net...

无线投屏-商业广告机无线投屏(消费级无线投屏器)

无线投屏-商业广告机无线投屏传统广告机与无线投屏的整合是信发行业的发展趋势,必捷广告机无线投屏解决方案解决了传统信息发布系统向智能化信息发布系统的灵活转变,支持智能手机、PC随时随地的灵活无线投屏,广...

C#程序设计_窗体(c#做窗体程序)

一、窗体中控件的自适应该实例用了控件的Dock和Anchor属性。Anchor:指定控件距容器边缘的距离;Dock:指定控件绑定到容器的边框。为直观地展示修改后的变化,将修改属性的代码绑定到Butto...

掌握 C# 和 .NET:常用术语与概念(c#的概念)

在群里看到一则招聘信息,《基本功扎实,对DDD、OO、IOC、AOP等有深刻认识,熟悉常用设计模式。》OO是什么??查了一下原来OO原来指的是面向对象编程(OOP),于是就总结了一些常用的术语...

C#反射(C#反射)

一、概念反射提供描述程序集、模块和类型的对象(Type类型)。可以使用反射动态创建类型的实例,讲类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。反射可以理解为操作meta...

HybridCLR——划时代的Unity原生C#热更新技术

HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生C#热更方案。HybridCLR扩充了IL2CPP的代码,使它由纯AOTRuntime变成“AOT+Inter...

c#常用打印框架示例及代码实现(c#打印控件)

usingSystem.Drawing.Printing;usingSystem.Windows.Forms;publicpartialclassMainForm:Form{//声明...

C#-值传递与引用传递的区别,使用ref与out的区别 086

值类型与引用类型简单来说就是将值类型变量或引用类型变量作为参数传入方法操作后原值的变化简单回顾,之前细说过值类型与引用类型的区别在内存中的变化,因此不再赘述1)内存中的区别:值类型主要存储在栈中;引用...

从零开始使用特性(Attribute)在C#中实现AOP功能

面向方面编程(Aspect-OrientedProgramming,简称AOP)是一种编程范式,它通过分离横切关注点(如日志记录、事务管理、安全等)来提高代码的可维护性。AOP可以帮助我们将这些分散...