MySQL InnoDB引擎锁的总结
为什么要锁
我们开的的各式各样系统中,系统运行需要CPU、内存、I/O、磁盘等等资源。但除了硬资源外,还有最为重要的软资源:数据。
当人们访问操作我们的系统时,其实归根是对数据的查看与生产。那么对于同一份数据,如果多个用户同时对它查看、修改时会出现什么问题呢?这必然会带来竞争,而为了控制并发的读取、修改数据会对数据造成的不一致、错乱等问题,数据库引入了锁的机制。
当然锁的问题解决了并发访问数据的问题,而不可避免的会对系统的性能产生负面影响。总结一下各种锁的使用场景方便在实践中更好的运用它从而提升系统性能。
锁的种类
我们日常开发中用到最多的存储引擎是Innodb 与 MyISAM两种,而 Innodb 现在更多是首选,因此主要是对 Innodb 的说明,MyISAM 跟多是作为一个对比的角色。

MySQL的锁可以按照多种方式进行划分,这里使用最常用的两种方式进行划分:粒度与使用方式。
需要特别说明的是:乐观锁与悲观锁并不是数据库中实现的锁机制,是需要我们自己去实现的。它是一种思想,我们不仅仅可以用在MySQL中,其它地方有需要的也可以用到。而像悲观锁它也是利用数据库现有的机制进行实现的。下面先根据不同分类对说明相关概念。
按使用方式
乐观锁 机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用。
悲观锁 具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
按粒度
表级锁 是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁分为表共享读锁与表独占写锁。
行级锁 是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。
页级锁 是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折中的页级,一次锁定相邻的一组记录。BDB支持页级锁。
这里需要说明的是,悲观锁是一种思想,它的实现是使用了 共享锁与排他锁来实现的。因此悲观锁本身并不是MySQL实现的锁机制,它是我们造出来的一个概念。
InnoDB中加锁
InnoDB 实现了两种类型的行锁,共享锁(S)与排他锁(X)。然后由于 InnoDB引擎又支持表级锁,所以它内部又有意向共享锁(IS)与意向排他锁(IX)。这两种表锁,都是InnoDB内部自动处理,换句话说我们写代码是无法控制也不需要控制的。我们能控制的是S与X锁。
为MySQL加锁
在日常操作中,UPDATE、INSERT、DELETE InnoDB会自动给涉及的数据集加排他锁,一般的 SELECT 一般是不加任何锁的。我们可以使用以下方式显式的为 SELECT 加锁。
共享锁:select * form table where id = 10 lock in share mode
排他锁:select * from table where id = 10 for update
那么什么时候该用共享锁什么时候用排他锁呢?
一般来讲,共享锁主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作(包括加锁的事物也只能读)。简单说就是大家都可以读数据,但是无法修改(更新或者删除),因此我认为共享锁也是悲观锁的一种实现。
排他锁是与共享锁相对应,自身加排他锁的事物能够自己发起修改操作,其它事物无法再对该数据加共享或者排他锁。
这里需要注意上面说到的一点,由于InnoDB引擎是行锁,不管我们在这条数据上加了共享锁还是排他锁,简单的select语句依然可以使用的,因为默认在InnoDB中select是不加锁的。
这里还有一点,上图中我们写到一个 间隙锁,这是什么东西?比如:当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。它存在的主要目的有一个是为了解决幻读问题,因为RR作为InnoDB的默认事物隔离级别,是存在幻读问题的,而我们在实际操作中确没有出现,就是因为这里做了处理。
关于乐观锁是如何加锁的,这个不同系统有不同的实现,简单来说,对每一个数据维护一个版本号,每次读取时把版本号读取出来,更新时版本号+1。然后更新时将读取的版本号作为条件,如果有其它事物更新了,那么必然会导致版本号变化,因为本次更新不会成功。这种机制最大程度的保证了并发。
InnoDB什么时候会锁表
InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能
总结
- 悲观锁与乐观锁是一种思想,而不是数据库锁机制的实现;
- InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁;
- 虽然根据标准InnoDB的默认事务隔离级别RR是存在幻读,但是通过间隙锁以及MVCC解决了幻读的问题;
- 间隙锁的存在会导致并发插入问题,尽量减少范围查询;
- InnoDB的索引设计非常重要。
MySQL InnoDB引擎锁的总结的更多相关文章
- 巧用MySQL InnoDB引擎锁机制解决死锁问题(转)
该文会通过一个实际例子中的死锁问题的解决过程,进一步解释innodb的行锁机制 最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深 ...
- Mysql InnoDB行锁实现方式(转)
Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...
- Mysql InnoDB行锁实现方式
Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...
- Mysql InnoDB引擎下 事务的隔离级别
mysql InnoDB 引擎下事物学习 建表user CREATE TABLE `user` ( `uid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, ...
- [MySQL]InnoDB引擎的行锁和表锁
1.行锁和表锁 在mysql 的 InnoDB引擎支持行锁,与Oracle不同,mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描, 行锁则 ...
- mysql innodb 引擎
innodb 引擎 一.概述 InnoDB 是一个用的比较广泛的存储引擎,因为它支持事物和外键,还有不错的效率;我们先看看官方教程怎么说; 我们先读一下, 对于上面的文档, 对一个InnoDB的表首先 ...
- 从一个死锁看mysql innodb的锁机制
背景及现象 线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作.经过DBA的分析,是某一张表的insert操 作和delete操作发生了死锁.简单介绍下数据库的情况(因为涉及到 ...
- MySQL Innodb引擎和MyIASM引擎的区别
Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别.该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL ...
- Mysql Innodb 间隙锁浅析
间隙锁说明 innodb引擎自动使用间隙锁来避免幻读(原因是因为innodb采用单行锁+间隙锁组合而成的行锁,会锁定一个范围和记录本身的行),参数默认innodb_locaks_unsafe_for_ ...
随机推荐
- Java 中的静态内部类
静态内部类是 static 修饰的内部类,这种内部类的特点是: 1. 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 2. 如果外部类的静态成员与内部类的成 ...
- 【1】记一次破解wifi
当然,使用的依旧是aircrack套件,这次依旧是跑字典,今天,捉到了另一个实验室icephone的wpa握手包,我猜测实验室的wifi一般都跟自己的名字有关,icephone刚好是8位字母,于是我就 ...
- 【Git/GitHub学习笔记】基本操作——创建仓库,本地、远程同步等
近日想分享一些文件,但是用度盘又太麻烦了(速度也很恶心).所以突发奇想去研究了下GitHub的仓库,这篇文章也就是一个最最最基础的基本操作.基本实现了可以在GitHub上存储文本信息与代码. 由于我的 ...
- Ubuntu终端里面显示路径名称太长,怎么设置变短【转】
转自:http://blog.csdn.net/id19870510/article/details/8276914 $: sudo vi ~/.bashrc 这个文件记录了用户终端配置 找到 if ...
- Deep Learning基础--CNN的反向求导及练习
前言: CNN作为DL中最成功的模型之一,有必要对其更进一步研究它.虽然在前面的博文Stacked CNN简单介绍中有大概介绍过CNN的使用,不过那是有个前提的:CNN中的参数必须已提前学习好.而本文 ...
- problems when installed mysql in linux ubuntu
reference:http://www.jb51.net/article/87160.htm?pc 1.ERROR 2002 (HY000): Can't connect to local MySQ ...
- ie6下面不支持!important的处理方法
例子: #box { color:red !important; color:blue; } 这个例子应该是大家经常见到的important的用法了,在IE6环境下,这行字是蓝色 ...
- PHP定界符出现错误
Parse error: syntax error, unexpected end of file, expecting variable (T_VARIABLE) or heredoc end (T ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记2——透明贴图,动画技术
第5章 透明贴图 像这样直接贴图会产生这种情况,所以我们需要透明贴图. 透明遮罩法:主要利用BitBlt函数中Raser(光栅)值的运算,需要准备素材图和遮罩图: 这个方法的原理解释见书131页. 示 ...
- redis之(十一)redis实现缓存的功能
[一]redis实现缓存的原理 --->利用键的失效时间设置实现缓存技术 --->由于redis的内存有限,可以在redis的配置文件里设置maxmemory的参数.来限制redis最大可 ...