【MySQL】--数据库锁机制
锁概述理论
锁是计算机协调多个进程或线程并发访问某一资源的机制。
在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争抢以外,数据也是一种供需多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的问题,锁冲突也是影响数据库并发访问的一个重要因素。从这个角度来说,锁对数据库而言尤其重要,也更加复杂。
锁的分类
从对数据的操作类型分:
读锁(共享锁)
针对同一份数据,多个读操作可以同时进行而不会互相影响
写锁(排它锁)
当前操作没有完成前,它会阻断其他写锁和读锁
从对数据操作的粒度分:
表锁(偏读)
偏向MyISAM存储引擎,开销小,加锁快;
锁粒度大,发生锁冲突的概率最高,并发度最低
案例
读锁
建表
CREATE TABLE `mylock` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;insert into mylock(name) valuse ('a');
insert into mylock(name) valuse ('b');
insert into mylock(name) valuse ('c');
insert into mylock(name) valuse ('d');
insert into mylock(name) valuse ('e');
加读锁:
lock table mylock read;
左边会话给mylock表加读锁。
验证读操作:
两个会话都可以读该表
自己不能再读其他表,其他会话不影响读
验证写操作:
左边写失败,右边写阻塞。
解锁后,右边阻塞解除并执行成功。
小结
加读锁后可以读、可以写该表;在解除读锁前,不能操作其他表。
其他会话可以读该表和其他表,但是对该表的写操作会阻塞,直至解锁。
其他会话不能解锁。
写锁
在左边给mylock表加写锁
左边可以读、写该表,但是不能读、写其他表
在解锁前,右边读、写该表都会阻塞,不影响操作其他表。
小结
加写锁后可以读、写该表,且解锁前不能读、写其他表
其他会话可以读、写其他表,原会话解锁前不能读、写该表
表锁分析
可以通过检查table_locks_waited
和table_locks_immediate
状态变量来分析系统上的表锁定:
show status like 'table%';
这里有两个状态变量记录MySQL内部表级锁定的情况,两个变量说明如下:
- Table_locks_immediate
产生表级锁定的次数,表示可以立即获取锁的查询次数,没立即获取锁值加1 - Table_locks_waited
出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,等待每一次锁值加1),此值高则说明存在较严重的表级锁争用情况
此外,MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎,因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。
总结
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁;在实行增删改操作前,会自动给涉及的表加写锁。
MySQL的表级锁有两种模式:表共享锁、表独占锁
锁类型 | 是否兼容 | 读锁 | 写锁 |
---|---|---|---|
读锁 | 是 | 是 | 否 |
写锁 | 是 | 否 | 否 |
结合上表,对MyISAM表进行操作,会有以下情况:
- 对MyISAM表的额度操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有对读锁释放后,才会执行其他进程的写操作。
- 对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作
简而言之,就是读锁会阻塞写,但是不会阻塞读;而写锁则会把读和写都阻塞。
行锁(偏写)
偏向InnoDB存储引擎,开销大,加锁慢;
会出现死锁;
锁定粒度最小,发生锁冲突的概率最低,并发度也高
InnoDB 和 MyISAM 两个最大不同点:
支持事务
采用行级锁
事务及ACID属性
事务:是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,简称ACID属性
原子性(Atomicity):事务是一个院子操作单元,其对数据的修改,要么全执行,要么全不执行
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的
隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然
持久性(Durable):事务完成之后,它对于数据的修改时永久性的,及时出现系统故障也能保持
并发事务处理带来的问题
更新丢失:当两个或多个事务选择同一行,然后基于最初选定的值更新行时,由于每个事务都不知道其他事务的存在(隔离性),就会发生丢失更新问题–最后更新覆盖了由其它事务所做的更新
脏读:事务A读取了事务B已修改但尚未提交的数据,还在这个基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
不可重复读:是指事务A两次读取某个数据的结果不同,这是由于事务A第一次读取后、第二次读取前,事务B对该数据进行了 修改。
幻读:同样事务A两次读取结果不同,这是由于事务A第一次读取后、第二次读取前,事务B对该数据进行了 新增。
数据库隔离级别
脏读、不可重复读、幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决,
事务隔离级别 | 读数据一致性 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
已提交读(read uncommitted) | 最低级别,只能保证不读取物理上损坏的数据 | 是 | 是 | 是 |
未提交读(read committed) | 语句级别 | 否 | 是 | 是 |
可重复读(repeatable read) | 事务级别 | 否 | 否 | 是 |
可序列化(serializable) | 最高级别,事务级 | 否 | 否 | 否 |
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
查看当前数据库的事务隔离级别:
show variables like 'tx_isolation';
默认:可重复读
案例
建表:
CREATE TABLE `test_innodb_lock` (`a` int(11) DEFAULT NULL,`b` varchar(16) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `test_innodb_lock` VALUES (1, 'b2');
INSERT INTO `test_innodb_lock` VALUES (3, '3');
INSERT INTO `test_innodb_lock` VALUES (4, '4000');
INSERT INTO `test_innodb_lock` VALUES (5, '5000');
INSERT INTO `test_innodb_lock` VALUES (6, '6000');
INSERT INTO `test_innodb_lock` VALUES (7, '7000');
INSERT INTO `test_innodb_lock` VALUES (8, '8000');
INSERT INTO `test_innodb_lock` VALUES (9, '9000');
INSERT INTO `test_innodb_lock` VALUES (1, 'b1');
创建索引:
CREATE INDEX test_innodb_a_ind on test_innodb_lock(a);CREATE INDEX test_innodb_lock_b_ind on test_innodb_lock(b);
关闭自动提交:
MySQL自5.5以后默认的存储引擎是InnoDB,每个写操作结束都会默认提交,为了演示行锁,需要关闭
set autocommit=0;
更新同一行数据:
左边更新成功且能查看到,不提交时,右边看不到更新。
提交:
左右都需commit。
同时更新同一行数据:
后更新的会话会阻塞,直到前面提交。
前面提交后,后者会执行成功或者等待超时报错
更新不同行数据:
两个会话都不会阻塞,提交后互相能看到更新结果
索引失效,导致行锁变表锁
由于字段b是字符串类型,左边SQL语句中有默认类型转换,导致索引失效,使得行锁升级为表锁,右边阻塞。
间隙锁及其危害
间隙锁: 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给复合条件的已有数据记录的索引项加锁;碎玉键值在条件范围内但并不存在的记录,就叫做“间隙(GAP)”。
InnoDB会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-Key锁)
危害:
因为Query执行过程中通过范围查找的话,他会锁定整个范围内的所有索引键值,即使这个键值不存在。
间隙锁有一个致命弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜锁定,而造成在锁定时无法插入锁定范围内的任何数据。在某些情况下可能会对性能造成很大危害。
提交后可以看到更新
如何锁定一行
总结
InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁要高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定。当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就会有比较明显的优势。
但是,InnoDB的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让InnoDB的整体性能表现不仅不能比MyISAM高,甚至可能更差。
【MySQL】--数据库锁机制相关推荐
- Mysql 数据库锁机制浅析
锁机制根据不同的存储引擎表现不一样,下面分析MyISAM存储引擎与InnoDB两种存储引擎. 一,MyISAM 1,该引擎采用的是表级锁,有: 读锁:表级读共享锁: 写锁:表级独占锁. 具体表现为: ...
- MySQL数据库锁机制之MyISAM引擎表锁和InnoDB行锁详解
MySQL中的锁概念 Mysql中不同的存储引擎支持不同的锁机制.比如MyISAM和MEMORY存储引擎采用的表级锁,BDB采用的是页面锁,也支持表级锁,InnoDB存储引擎既支持行级锁,也支持表级锁 ...
- MySQL数据库——锁机制
1 认识锁机制 在认识锁机制前,首先思考一个问题:在同一时刻,用户A和用户B同时要获取并修改sh_goods表中id等于2的stock库存量值,此时会发生什么呢? 假设在初始情况下,sh_ goods ...
- 轻松掌握mysql数据库锁机制的相关原理_轻松掌握MySQL数据库锁机制的相关原理...
不同于行级或页级锁定的选项: · 版本(例如,为并行的插入在MySQL中使用的技术),其中可以一个写操作,同时有许多读取操作.这明数据库或表支持数据依赖的不同视图,取决于访问何时开始.其它共同的术语是 ...
- 带你了解什么是MySQL数据库(八)数据库锁机制
目录 数据库的锁机制 锁的分类 MySQL中的行级锁,表级锁,页级锁(粒度) 行级锁之共享锁与排他锁(级别) innodb存储引擎的锁机制 行级锁与表级锁区分 三种行锁算法 死锁问题 什么时候使用表锁 ...
- MySQL数据库读现象 数据库锁机制 Innodb存储引擎行级锁
数据库读现象 数据库管理软件的"读现象"指的是当多个事务并发执行时,在读取数据方面可能碰到的问题,包括有脏读.不可重复读和幻读. 创建数据表 # 创建数据表 create tabl ...
- 数据库锁机制为什么很重要?
前言 在座的朋友们,你们的时间够用吗?想要成为一个成功的人吗?如果你们都有这样的疑惑,那就保持一刻谦虚的心态,跟着罗老师学习时间管理吧! 毕竟时间管理大师是一个用户访问多个资源,今天咱们来讲讲当多个用 ...
- Mysql的锁机制之表锁
Mysql的锁机制之表锁 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除传统的计算资源(如CPU,RAM,I/O等)的争用外,数据也是一种供许多用户共享的资源,如何保证数据并发访 ...
- MySQL调优(八):查缺补漏(mysql的锁机制,读写分离,执行计划详解,主从复制原理)
mysql的锁机制 1.MySQL锁的基本介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共 ...
- MySQL数据库锁介绍
MySQL数据库锁介绍 1. 锁的基本概念 当并发事务同时访问一个资源时,有可能导致数据不一致,因此需要一种机制来将数据访问顺序化,以保证数据库数据的一致性. 锁就是其中的一种机制. 我们可以用商场的 ...
最新文章
- 张钹院士:制约人工智能发展的最大困难是什么?
- Processing 字体变形
- vue 新窗口打开外链接
- PCA对特征点描述子降维
- 好迷茫! 工作几年除了写代码,其他啥也不会
- 北京、深圳 | 百度视觉算法研发实习生 人脸活体方向
- pre保持原格式但文本不超出的解决方案
- Halcon教程二:内置实例程序库
- 计算机 英语简历,2017计算机英文简历范文
- 深度学习与神经网络的异同
- PAT 1010 月饼
- 餐巾计划问题【网络流24题】
- JavaScript数组属性和方法
- gradle 设备未就绪。解决方法
- 四川成都攻防大赛技术细节
- VBA写入公式(2):日期公式集
- python取值范围到无穷大_python的特殊数字类型(无穷大、无穷小等)
- PAL制式视频信号的处理
- win10查看USB设备接入记录
- 父元素flex:1,子元素设置高度百分百无效