目录

1、MySQL锁的基本介绍

2、MyISAM表锁

2.1写锁阻塞读

2.2读阻塞写

3、InnoDB锁

3.1、事务及其ACID属性

3.2、并发事务带来的问题

3.3.1、在不通过索引条件查询的时候,innodb使用的是表锁而不是行锁

3.3.2、创建带索引的表进行条件查询,innodb使用的是行锁

总结


1、MySQL锁的基本介绍

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的 计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

​ 相对其他数据库而言,MySQL的锁机制比较简单,其最 显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 ​

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

​ 从上述特点可见,很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适!仅从锁的角度 来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有 并发查询的应用,如一些在线事务处理(OLTP)系统。

2、MyISAM表锁

MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)表独占写锁(Table Write Lock)

对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;对 MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;MyISAM表的读操作与写操作之间,以及写操作之间是串行的!

建表语句:

CREATE TABLE `mylock` (`id` int(11) NOT NULL AUTO_INCREMENT,`NAME` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;INSERT INTO `mylock` (`id`, `NAME`) VALUES ('1', 'a');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('2', 'b');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('3', 'c');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('4', 'd');

2.1写锁阻塞读

当一个线程获得对一个表的写锁之后,只有持有锁的线程可以对表进行更新操作。其他线程的读写操作都会等待,直到锁释放为止。

session1 session2
获取表的write锁定<br />lock table mylock write;  
当前session对表的查询,插入,更新操作都可以执行<br />select * from mylock;<br />insert into mylock values(5,'e'); 当前session对表的查询会被阻塞<br />select * from mylock;
释放锁:<br />unlock tables; 当前session能够立刻执行,并返回对应结果

2.2读阻塞写

一个session使用lock table给表加读锁,这个session可以锁定表中的记录,但更新和访问其他表都会提示错误,同时,另一个session可以查询表中的记录,但更新就会出现锁等待。

session1 session2
获得表的read锁定<br />lock table mylock read;  
当前session可以查询该表记录:<br />select * from mylock; 当前session可以查询该表记录:<br />select * from mylock;
当前session不能查询没有锁定的表<br />select * from person<br />Table 'person' was not locked with LOCK TABLES 当前session可以查询或者更新未锁定的表<br />select * from mylock<br />insert into person values(1,'zhangsan');
当前session插入或者更新表会提示错误<br />insert into mylock values(6,'f')<br />Table 'mylock' was locked with a READ lock and can't be updated<br />update mylock set name='aa' where id = 1;<br />Table 'mylock' was locked with a READ lock and can't be updated 当前session插入数据会等待获得锁<br />insert into mylock values(6,'f');
释放锁<br />unlock tables; 获得锁,更新成功

注意:

MyISAM在执行查询语句之前,会自动给涉及的所有表加读锁,在执行更新操作前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要使用命令来显式加锁,上例中的加锁时为了演示效果。

MyISAM的并发插入问题

MyISAM表的读和写是串行的,这是就总体而言的,在一定条件下,MyISAM也支持查询和插入操作的并发执行。

可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺:

mysql> show status like 'table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 352   |
| Table_locks_waited    | 2     |
+-----------------------+-------+

--如果Table_locks_waited的值比较高,则说明存在着较严重的表级锁争用情况。

3、InnoDB锁

3.1、事务及其ACID属性

事务是由一组SQL语句组成的逻辑处理单元,事务具有4属性,通常称为事务的ACID属性。

原子性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

3.2、并发事务带来的问题

相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多用户的并发操作,但与此同时,会带来一下问题:

脏读: 一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”

不可重复读:一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。

幻读: 一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”

上述出现的问题都是数据库读一致性的问题,可以通过事务的隔离机制来进行保证。

数据库的事务隔离越严格,并发副作用就越小,但付出的代价也就越大,因为事务隔离本质上就是使事务在一定程度上串行化,需要根据具体的业务需求来决定使用哪种隔离级别

脏读 不可重复读 幻读
read uncommitted
read committed  
repeatable read    
serializable      

可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:

mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 18702 |
| Innodb_row_lock_time_avg      | 18702 |
| Innodb_row_lock_time_max      | 18702 |
| Innodb_row_lock_waits         | 1     |
+-------------------------------+-------+
--如果发现锁争用比较严重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高

3.3、InnoDB的行锁模式及加锁方法

共享锁(s):又称读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。​ 排他锁(x):又称写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。

​ mysql InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。

InnoDB行锁实现方式

​ InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

3.3.1、在不通过索引条件查询的时候,innodb使用的是表锁而不是行锁

create table tab_no_index(id int,name varchar(10)) engine=innodb;
insert into tab_no_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
session1 session2
set autocommit=0<br />select * from tab_no_index where id = 1; set autocommit=0<br />select * from tab_no_index where id =2
select * from tab_no_index where id = 1 for update  
  select * from tab_no_index where id = 2 for update;

session1只给一行加了排他锁,但是session2在请求其他行的排他锁的时候,会出现锁等待。原因是在没有索引的情况下,innodb只能使用表锁。

3.3.2、创建带索引的表进行条件查询,innodb使用的是行锁

create table tab_with_index(id int,name varchar(10)) engine=innodb;
alter table tab_with_index add index id(id);
insert into tab_with_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
session1 session2
set autocommit=0<br />select * from tab_with_indexwhere id = 1; set autocommit=0<br />select * from tab_with_indexwhere id =2
select * from tab_with_indexwhere id = 1 for update  
  select * from tab_with_indexwhere id = 2 for update;

3、由于mysql的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是依然无法访问到具体的数据

insert into tab_with_index  values(1,'4');
session1 session2
set autocommit=0 set autocommit=0
select * from tab_with_index where id = 1 and name='1' for update  
  select * from tab_with_index where id = 1 and name='4' for update<br />虽然session2访问的是和session1不同的记录,但是因为使用了相同的索引,所以需要等待锁

总结

对于MyISAM的表锁,主要讨论了以下几点: (1)共享读锁(S)之间是兼容的,但共享读锁(S)与排他写锁(X)之间,以及排他写锁(X)之间是互斥的,也就是说读和写是串行的。 (2)在一定条件下,MyISAM允许查询和插入并发执行,我们可以利用这一点来解决应用中对同一表查询和插入的锁争用问题。 (3)MyISAM默认的锁调度机制是写优先,这并不一定适合所有应用,用户可以通过设置LOW_PRIORITY_UPDATES参数,或在INSERT、UPDATE、DELETE语句中指定LOW_PRIORITY选项来调节读写锁的争用。 (4)由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM表可能会出现严重的锁等待,可以考虑采用InnoDB表来减少锁冲突。

对于InnoDB表,本文主要讨论了以下几项内容: (1)InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。 (2)在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同。

在了解InnoDB锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:

  • 尽量使用较低的隔离级别; 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会;

  • 选择合理的事务大小,小事务发生锁冲突的几率也更小;

  • 给记录集显式加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁;

  • 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会;

  • 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响; 不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁;

  • 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。

参考《马士兵教育》相关视频内容

MySQL锁机制(myisam表所与innoDB锁)相关推荐

  1. mysql三锁,mysql锁机制之表锁(三)

    顾名思义,表锁就是一锁锁一整张表,在表被锁定期间,其他事务不能对该表进行操作,必须等当前表的锁被释放后才能进行操作.表锁响应的是非索引字段,即全表扫描,全表扫描时锁定整张表,sql语句可以通过执行计划 ...

  2. Mysql的锁机制之表锁

    Mysql的锁机制之表锁 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除传统的计算资源(如CPU,RAM,I/O等)的争用外,数据也是一种供许多用户共享的资源,如何保证数据并发访 ...

  3. SQL SERVER的锁机制(二)——概述(锁的兼容性与可以锁定的资源)

    二.完整的锁兼容性矩阵(见下图) 对上图的是代码说明:见下图. 三.下表列出了数据库引擎可以锁定的资源. 名称 资源 缩写 编码 呈现锁定时,描述该资源的方式 说明 数据行 RID RID 9 文件编 ...

  4. Linux 锁机制(3)之自旋锁

    Linux 锁机制(3)之自旋锁 1. 自旋锁 1.1 两种锁 1.2 自旋锁 1.3 自旋名字来源:自旋锁一直循环等待,直到获取锁为止. 1.4 自旋锁优点: 2 自旋锁特点/使用: 2.1 临界区 ...

  5. MySQL中的锁机制、MyISAM表锁、MyISAM表级锁争用情况、MyISAM并发插入Concurrent Inserts、MyISAM的锁调度

    前言: 关于读锁.写锁.乐观锁.悲观锁.行锁.表锁的理解可以看看以前我写的: 读锁.写锁.乐观锁.悲观锁.行锁.表锁 内部锁:在MySQL服务器内部执行的锁,以管理多个会话对表内容的争用.这种类型的锁 ...

  6. mysql更新锁机制_mysql查询更新时的锁表机制分析

    欢迎进入Linux社区论坛,与200万技术人员互动交流 >>进入 为了给高并发情况下的mysql进行更好的优化,有必要了解一下mysql查询更新时的锁表机制. 一.概述 MySQL有三种锁 ...

  7. 阿里云mysql不让锁表_MySQL中InnoDB锁不住表的原因

    MySQL中InnoDB锁不住表是因为如下两个参数的设置: mysql> show variables like '%timeout%'; +-------------------------- ...

  8. mysql锁机制(共享锁(S)、排他锁(X)、意向共享锁(IS)、意向排他锁(IX)的关系,死锁,乐观锁,悲观锁...)

    1. 锁的基础与行锁的特点 1.1 概念 在开发多用户.数据库驱动的应用时,相当大的一个难点就是解决并发性的问题,目前比较常用的解决方案就是锁机制. 锁机制也是数据库系统区别于文件系统的一个关键特性. ...

  9. mysql引擎机制_MySQL引擎特性:InnoDB同步机制

    towake up possible hanging threads if they are missed inmutex_signal_object. */ if (mutex->waiter ...

最新文章

  1. 自监督学习新思路!基于蒸馏损失的自监督学习算法 | CVPR 2021
  2. 【面试题】你知道为什么HashMap是线程不安全的吗?
  3. 操作系统课设--NACHOS试验环境准备、安装与MAKEFILE分析
  4. MCtalk教育快报 | 0820
  5. 【ArcGIS遇上Python】ArcGIS Python批处理入门到精通实用教程目录
  6. 网络编程-网络分层的意义
  7. serialport通过usb通讯_IOT串口通讯-RS232/RS485
  8. 命名管道实现进程的信息传递【mkfifo函数、open函数】
  9. MySQL保留关键字
  10. 【SpringSecurity系列02】SpringSecurity 表单认证逻辑源码解读
  11. 机器学习教程 一-不懂这些线性代数知识 别说你是搞机器学习的
  12. 关于Redis Cluster的几个问题
  13. 关于ecshop模板更新版本的解决方法(三)
  14. 字节跳动算法工程师总结:中高级java开发面试题
  15. factory setup 序列号_麻烦哪位大侠帮我把改一下setup factory 中生成16位注册码的脚本,(在线等)急!!!...
  16. NandFlash介绍、操作流程分析以及S5PV210的NandFlash控制器介绍
  17. 无法获得 VMCI 驱动程序的版本: 句柄无效解决
  18. Win10怎么关闭开机启动项
  19. 浅谈现代计算机产业革命
  20. 【马克思主义基本原理概论】

热门文章

  1. SAP固定资产相关的一些表
  2. SMW0上传文件到数据库层详解
  3. SM13: 分析SAP事务提交时的FM调用
  4. 指针传递内表方式做smartforms
  5. 2020前三季度各省市人均收入来了!看看你的家乡排第几?
  6. “五心”知“五感”,平安打造有温度的智慧城市
  7. java 句柄池_深入理解JVM之Java对象的创建、内存布局、访问定位详解
  8. error: a label can only be part of a statement and a declaration is not a statement
  9. 2016大一计算机基础操作题,2016大学计算机基础试题及答案
  10. 区间比较_Simulink(离散PIDamp;区间检测模块)+AURIX功能安全板过流比较电路+电机结构应用与工作原理学习网站...