mysql innodb 全表锁,Mysql InnoDB行锁及表锁分享

一. 背景知识

二. 步入正题:表锁和行锁

1.1. 表锁 vs 行锁

在 MySQL 中锁的种类有很多,但是最基本的还是表锁和行锁:表锁指的是对一整张表加锁,一般是 DDL 处理时使用,也可以自己在 SQL 中指定;而行锁指的是锁定某一行数据或某几行,或行和行之间的间隙。行锁的加锁方法比较复杂,但是由于只锁住有限的数据,对于其它数据不加限制,所以并发能力强,通常都是用行锁来处理并发事务。表锁由 MySQL 服务器实现,行锁由存储引擎实现,常见的就是InnoDb,所以通常我们在讨论行锁时,隐含的一层意义就是数据库的存储引擎为 InnoDb ,而 MyISAM 存储引擎只能使用表锁。

1.2. 表锁

表锁由 MySQL 服务器实现,所以无论你的存储引擎是什么,都可以使用。一般在执行 DDL 语句时,譬               如 ALTER TABLE 就会对整个表进行加锁。在执行 SQL 语句时,也可以明确对某个表加锁。

1.2.1 操作演示(user_test创建表脚本见2.4.1)

-- 事物A中 显示对 user_test 加上读锁locktableuser_test read;select*fromuser_testwhereid=3;  -- 此时事物B中对其进行update或者write操作start TRANSACTION;-- 手动开启事物insertintouser_test(age,name)values(18,'Tom');

结论:此时事物B一致处于等待事物A释放锁的状态,最终会回去锁超时

2.1. 行锁(以下验证是在默认的隔离级别(可重复读的事务隔离级)下操作)

InnoDB  NEXT-KEY Locks,解决了在可重复读的事务隔离级别下出现幻读的问题。

什么是幻读?

幻读是在可重复读的事务隔离级别下会出现的一种问题,简单来说,可重复读保证了当前事务不会读取到其他事       务已提交的 UPDATE 操作。但同时,也会导致当前事务无法感知到来自其他事务中的 INSERT 或 DELETE 操       作,这就是幻读。

2.2. 关于行锁我们要知道的

行锁在 InnoDB 中是基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁。

2.3 行锁分类

2.3.1 从加锁范围划分

a)记录锁(Record Locks):存在与唯一索引包括主键索引 顾名思义,记录锁就是为某行记录加锁,它封锁该行的索引记录:

b)间隙锁(Gap Locks):

存在与非唯一索引中,锁定开区间范围内的一段间隔,它是基于临键锁实现的。

间隙锁基于非唯一索引,它锁定一段范围内的索引记录。间隙锁基于下面将会提到的Next-Key Locking 算法,请务必牢记:使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据。

是一种加在两个索引之间的锁,或者加在第一个索引之前,或最后一个索引之后的间隙。有时候又称为范围(Range Locks),这个范围可以跨一个索引记录,多个索引记录,甚至是空的。使用间隙锁可以防止其他事务在这个范围内插入或修改记录,保证两次读取这个范围内的记录不会变,从而不会出现幻读现象。很显然,间隙锁会增加数据库的开销,虽然解决了幻读问题,但是数据库的并发性一样受到了影响,所以在选择数据库的隔离级别时,要注意权衡性能和并发性,根据实际情况考虑是否需要使用间隙锁,大多数情况下使用 read committed 隔离级别就足够了,对很多应用程序来说,幻读也不是什么大问题。

产生间隙锁的条件(RR事务隔离级别下):

3.1.  使普通索引锁定;

3.2.  使用多列唯一索引;

3.3.  使用唯一索引锁定多行记录。

c)临键锁(Next-Key Locks)临键锁存在于非唯一索引中(主键中不存在临键锁),该类型的每条记录的索引上都存在这种锁,它是一种特殊的间隙锁,锁定一段左开右闭的索引区间。临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。

注意: Next-Key 可以理解为一种特殊的间隙锁,也可以理解为一种特殊的算法。通过临建锁可以解决幻读的问题。 每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。需要强调的一点是,InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁 , 但是存在间隙锁。临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

2.3.2  从兼容性和存在形态划分

a6bb8a1985db

2.4. 操作演示

2.4.1 创建测试表并初始化数据

CREATETABLE`user_test`(`id`bigint(20)unsignedNOTNULLAUTO_INCREMENT COMMENT'自增id',`age`int(11)unsignedNOTNULLCOMMENT'年龄',`name`varchar(16)NOTNULLCOMMENT'姓名',PRIMARY KEY(`id`)COMMENT'主键')ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='行锁测试表';INSERTINTO`user_test`(`id`,`age`,`name`)VALUES(1,10,'Lee');INSERTINTO`user_test`(`id`,`age`,`name`)VALUES(2,24,'Ted');INSERTINTO`user_test`(`id`,`age`,`name`)VALUES(3,32,'Zed');INSERTINTO`user_test`(`id`,`age`,`name`)VALUES(4,45,'Talon');

2.4.2Record lock 记录锁验证

执行一下sql

-- 事物A 中更新数据 sql如下:-- 手动开启事物或者 beginSTART TRANSACTION;-- 根据非唯一索引列 UPDATE 某条记录  (只会产生记录锁,不会产生间隙锁)UPDATEuser_testSETname='LISHI'WHEREid=2;-- 等观看完下面事物B在开启事物commit;rollback;-- 事物B 也同时更新统一条记录START TRANSACTION;UPDATEuser_testSETname='ZHANGSAN'WHEREid=2;commit;rollback;

此时事物B会出现如图结果

事物A commit 或者 rollback 此时事物B会拿到锁执行成功;事物B更新其他id记录不受影响:

START TRANSACTION;UPDATEuser_testSETname='ZHANGSAN'WHEREid=1;commit;

2.4.2Next-Key Locks 临键锁验证

首先在age字段上创建普通索引

ALTERTABLE`user_test` ADD INDEX `index_age`(`age`);

此时该表中 age 列潜在的临键锁有:

(-∞, 10],

(10, 24],

(24, 32],

(32, 45],

(45, +∞],

事物A 中更新数据 sql如下:

START TRANSACTION;-- 根据非唯一索引列 UPDATE 某条记录select*fromuser_testwhereage=10forupdate-- 事物B此时插入或者更新age小于10大于1的一条记录-- 插入一条记录为age=7的记录start TRANSACTION;insertintouser_test(age,name)values(7,'Tom');COMMIT;

-- 事物B更新其中一条记录age为8也会被阻塞(虽然条件id是主键索引,更新的字段是普通索引,因此也会加上间隙锁)start TRANSACTION;UPDATEuser_testSETage=8WHEREid=2;COMMIT;

此时事物B会出现如图结果

事物A commit 或者 rollback 此时事物B会拿到锁执行成功

2.4.3. Gap Locks 间隙锁验证

打开间隙锁设置首先查看 innodb_locks_unsafe_for_binlog 是否禁用:

show variableslike'innodb_locks_unsafe_for_binlog';

a6bb8a1985db

innodb_locks_unsafe_for_binlog:默认值为OFF,即启用间隙锁。因为此参数是只读模式,如果想要禁用间隙锁,需要修改my.cnf(windows是my.ini)重新启动才行。

默认mac是没有my.cnf文件的,因此要在 etc文件下创建 my.cnf文件(etc/my.cnf)

my.cnf内容如下(主要添加:)

innodb_locks_unsafe_for_binlog=1

3.my.cnf内容如下:

# Example MySQL config file formediumsystems.  #  # Thisisfor a system with little memory(32M-64M)whereMySQL plays# an important part,orsystems up to128MwhereMySQLisused together with# other programs(suchasa web server)  #  # MySQL programs look for option filesinasetof# locations which dependonthe deployment platform.  # You can copy this option file to one of those  # locations. For information about these locations,see:# http://dev.mysql.com/doc/mysql/en/option-files.html  #  #Inthis file,you can use alllongoptions that a program supports.# If you want to know which options a program supports,run the program# with the"--help"option.  # The following options will be passed to all MySQL clients  [client]default-character-set=utf8#password=your_passwordport=3306socket=/tmp/mysql.sock  # Here follows entries for some specific programs    # The MySQL server  [mysqld]character-set-server=utf8init_connect='SET NAMES utf8  port        = 3306    socket      = /tmp/mysql.sock    skip-external-locking    key_buffer_size = 16M    max_allowed_packet = 1M    table_open_cache = 64    sort_buffer_size = 512K    net_buffer_length = 8K    read_buffer_size = 256K    read_rnd_buffer_size = 512K    myisam_sort_buffer_size = 8M    character-set-server=utf8    init_connect='SETNAMES utf8'  innodb_locks_unsafe_for_binlog = 1# Don't listenona TCP/IP port at all. This can be a security enhancement,# if all processes that need to connect to mysqld runonthe same host.# All interaction with mysqld must be made via Unix socketsornamed pipes.# Note that using this option without enabling named pipesonWindows#(via the"enable-named-pipe"option)will render mysqld useless!#  #skip-networking # Replication Master Server(default)# binary loggingisrequired for replicationlog-bin=mysql-bin # binary logging format-mixed recommendedbinlog_format=mixed # required unique idbetween1and2^32-1# defaults to1if master-hostisnotset# but willnotfunctionasa master if omittedserver-id=1 # Replication Slave(comment out master section to use this)    #  # To configure this hostasa replication slave,you can choosebetween# two methods:    #  #1)Use the CHANGE MASTER TO command(fully describedinour manual)-#    the syntaxis:    #  #    CHANGE MASTER TO MASTER_HOST=,MASTER_PORT=,#    MASTER_USER=,MASTER_PASSWORD=;    #  #whereyou replace,,byquoted stringsand#bythe master's port number (3306 by default).      #      #    Example:      #      #    CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,      #    MASTER_USER='joe', MASTER_PASSWORD='secret';      #      # OR      #      # 2) Set the variables below. However, in case you choose this method, then      #    start replication for the first time (even unsuccessfully, for example      #    if you mistyped the password in master-password and the slave fails to      #    connect), the slave will create a master.info file, and any later      #    change in this file to the variables'valuesbelow will be ignoredand#    overriddenbythe content of the master.infofile,unless you shutdown#    the slave server,deletemaster.infoandrestart the slaver server.#    For that reason,you may want to leave the lines below untouched#(commented)andinstead use CHANGE MASTER TO(see above)    #  # required unique idbetween2and2^32-1#(anddifferentfromthe master)# defaults to2if master-hostisset# but willnotfunctionasa slave if omitted#server-id=2    #  # The replication master for this slave-required#master-host=    #      # The username the slave will use for authentication when connecting  # to the master-required#master-user=    #      # The password the slave will authenticate with when connecting to  # the master-required#master-password=    #  mysqld# The port the masterislisteningon.# optional-defaults to3306#master-port=    #  # binary logging-notrequired for slaves,but recommended#log-bin=mysql-bin      # Uncomment the following if you are using InnoDB tables  #innodb_data_home_dir=/usr/local/mysql/data#innodb_data_file_path=ibdata1:10M:autoextend#innodb_log_group_home_dir=/usr/local/mysql/data# You canset.._buffer_pool_size up to50-80%      # of RAM but beware of setting memory usage too high  #innodb_buffer_pool_size=16M#innodb_additional_mem_pool_size=2M#Set.._log_file_size to25%of buffer pool size#innodb_log_file_size=5M#innodb_log_buffer_size=8M#innodb_flush_log_at_trx_commit=1#innodb_lock_wait_timeout=50 [mysqldump]        quick  max_allowed_packet=16M [mysql]no-auto-rehash# Remove the next comment character if you arenotfamiliar with SQL#safe-updatesdefault-character-set=utf8 [myisamchk]key_buffer_size=20Msort_buffer_size=20Mread_buffer=2Mwrite_buffer=2M [mysqlhotcopy]interactive-timeout

此时再次查看间隙锁是否开启

a6bb8a1985db

唯一索引的间隙锁

-- 创建test表并插入一些数据CREATETABLE`test`(`id`int(1)NOTNULLAUTO_INCREMENT,`name`varchar(8)DEFAULTNULL,PRIMARY KEY(`id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERTINTO`test`VALUES('1','小罗');INSERTINTO`test`VALUES('5','小黄');INSERTINTO`test`VALUES('7','小明');INSERTINTO`test`VALUES('11','小红');

在进行测试之前,我们先来看看test表中存在的隐藏间隙:

(-∞, 1]

(1, 5]

(5, 7]

(7, 11]

(11, +∞]

-- 执行事物1如下START TRANSACTION;-- 查询 id 在 5 - 11 范围的数据并加记录锁 SELECT*FROM`test`WHERE`id`BETWEEN5AND11FORUPDATE;-- 事务B进行插入数据操作 --  注意:以下的语句不是放在一个事务中执行,而是分开多次执行,每次事务中只有一条添加语句START TRANSACTION;-- 事务2插入一条 id = 3,name = '小张1' 的数据 INSERTINTO`test`(`id`,`name`)VALUES(3,'小张1');# 正常执行-- 事务3插入一条 id = 4,name = '小白' 的数据INSERTINTO`test`(`id`,`name`)VALUES(4,'小白');# 正常执行-- 事务4插入一条 id = 6,name = '小东' 的数据INSERTINTO`test`(`id`,`name`)VALUES(6,'小东');# 阻塞-- 事务5插入一条 id = 8, name = '大罗' 的数据INSERTINTO`test`(`id`,`name`)VALUES(8,'大罗');# 阻塞-- 事务6插入一条 id = 9, name = '大东' 的数据INSERTINTO`test`(`id`,`name`)VALUES(9,'大东');# 阻塞-- 事务7插入一条 id = 11, name = '李西' 的数据INSERTINTO`test`(`id`,`name`)VALUES(11,'李西');# 阻塞-- 事务8插入一条 id = 12, name = '张三' 的数据INSERTINTO`test`(`id`,`name`)VALUES(12,'张三');# 正常执行-- 提交事务1,释放事务1的锁 COMMIT;

从上面我们可以看到,(5, 7]、(7, 11] 这两个区间,都不可插入数据,其它区间,都可以正常插入数据。所以我们可以得出结论:当我们给 (5, 7] 这个区间加锁的时候,会锁住 (5, 7]、(7, 11] 这两个区间。

我们再来测试如果我们锁住不存在的数据时,会怎样:

-- 开启事务1 START TRANSACTION;--  查询 id = 3 这一条不存在的数据并加记录锁 SELECT*FROM`test`WHERE`id`=3FORUPDATE;-- 延迟30秒执行,防止锁释放 SELECTSLEEP(30);-- # 注意:以下的语句不是放在一个事务中执行,而是分开多次执行,每次事务中只有一条添加语句--  事务2插入一条 id = 3,name = '小张1' 的数据 INSERTINTO`test`(`id`,`name`)VALUES(2,'小张1');# 阻塞--  事务3插入一条 id = 4,name = '小白' 的数据 INSERTINTO`test`(`id`,`name`)VALUES(4,'小白');# 阻塞-- 事务4插入一条 id = 6,name = '小东' 的数据 INSERTINTO`test`(`id`,`name`)VALUES(6,'小东');# 正常执行-- 事务5插入一条 id = 8, name = '大罗' 的数据 INSERTINTO`test`(`id`,`name`)VALUES(8,'大罗');# 正常执行-- 提交事务1,释放事务1的锁 COMMIT;

我们可以看出,指定查询某一条记录时,如果这条记录不存在,会产生间隙锁。

结论

对于指定查询某一条记录的加锁语句,如果该记录不存在,会产生记录锁和间隙锁,如果记录存在,则只会产生记录锁,如:WHERE `id` = 5 FOR UPDATE;

对于查找某一范围内的查询语句,会产生间隙锁,如:WHERE `id` BETWEEN 5 AND 7 FOR UPDATE;

总结:

上述文档是自己及其团队小伙伴们一起讨论的结果,自己做了一下总结,很感谢团队成员刘昌力、刘明远、朱文彬、祁世松、桑萌萌、石伟男以及彭绍翔等他们的讨论支持。

此文档是对行锁和表锁的一个粗略的认识,存在一定的不足、知识点的缺失、不完善等问题。希望大家能够一起再完善一下,共同学习进步,掌握知识技能,更好的正确高效的运用到平时的工作当中去,才是我们分享技术文档的意思所在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/441674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【牛客 - 185A】无序组数 (思维,数学,因子个数)

题干: 时间限制:C/C 1秒,其他语言2秒 空间限制:C/C 131072K,其他语言262144K 64bit IO Format: %lld 题目描述 给出一个二元组(A,B) 求出无序二元组(a,b) 使得&#x…

php万能查询用预,PHP 与 mysql

一、php 的 sql 注入攻击1.1、什么是 sql 注入攻击用户提交一段数据库查询代码,根据返回的结果,获得某些他想得到的数据。比如 :查询某个管理员是否存在,一般程序员会这么写$sql "select * from user where nameluluyii and…

php 判断radio选中哪个,jquery如何判断单选按钮radio是否选中

jquery判断单选按钮radio是否选中的方法:1、加载页面的时候获取id,代码为【var fs$("#"id).val()】;2、点击按钮的时候获取id,代码为【var id $(this).attr("id")】。本教程操作环境:windows7系统…

【qduoj】【超级楼梯进阶版】

题干: 描述 N级阶梯,人可以一步走一级,也可以一步走两级,求人从阶梯底端走到顶端可以有多少种不同的走法。 输入 一个整数n,代表台阶的阶数。 输出 求人从阶梯底端走到顶端可以有多少种不同的走法,输出结…

matlab在光学实验中的应用,matlab在光学实验中的应用

matlab在光学实验中的应用 《MATLAB》课程论文MATLAB 在光学实验中的应用姓名:学号:专业:班级:指导老师:学院:完成日期:1MATLAB 在波动光学中的应用(姓名:郑苗苗 12012241736 2012 级…

【HDU - 6016】Count the Sheep (思维,类似二分图)

题干: Altough Skipping the class is happy, the new term still can drive luras anxious which is of course because of the tests! Luras became worried as she wanted to skip the class, as well as to attend the BestCoder and also to prepare for test…

如何生成时间序列matlab,求助:在MATLAB里如何输入时间序列中的时间

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼function[logRS,logERS,V]RSana(x,n,method,q)%Syntax:[logRS,logERS,V]RSana(x,n,method,q)%____________________________________________%% Performs R/Sanalysis on a time series.%% logRS is thelog(R/S).% logERS is theEx…

【CF#192 A】Funky Numbers (二分,查找,二元组)

题干: As you very well know, this years funkiest numbers are so called triangular numbers (that is, integers that are representable as , where k is some positive integer), and the coolest numbers are those that are representable as a sum of two…

matlab考试试题,matlab-考试试题-

matlab-考试试题- MATLAB 考试试题 (1) 产生一个1x10的随机矩阵,大小位于( -5 5),并且按照从大到小的顺序排列好!(注:要程序和运行结果的截屏)答案:a10*rand(1,10)-5;bsort(a, descend )1.请产生一个100*5 的矩阵&…

【HDU - 1702 】ACboy needs your help again! (栈和队列,水题模拟)

题干: ACboy was kidnapped!! he miss his mother very much and is very scare now.You cant image how dark the room he was put into is, so poor :(. As a smart ACMer, you want to get ACboy out of the monsters labyrinth.But when you arrive at the g…

java中jframe不存在怎么办,java – 设置JFrame背景,为什么这不起作用?

打印加载图像的宽度(如果为-1)则图像未正确加载.img Toolkit.getDefaultToolkit().createImage("red.png");System.out.println(img.getWidth(null)); // check what it prints值得阅读Loading Images Using getResource上的Java Tutorial您可以根据图像位置尝试任何…

后盾网经典原创视频教程php,《后盾网经典原创视频教程:PHP》139集

目录0_1 后盾网_IIS环境下PHP开发环境安装0 后盾网_PHP集成环境安装视频教程1 PHP视频教程 PHP基础(一)2 PHP视频教程 PHP基础(二)3 PHP视频教程 PHP基础(三)4 PHP视频教程 数据类型(一)5 PHP视频教程 数据类型(二)6 PHP视频教程 数据类型(三)7 PHP视频教程 类型转换 外部变量8…

【HDU - 1022】Train Problem I (栈模拟,水题,思维)

题干: As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world ^v^). But here comes a proble…

【HDU - 1216 】Assistance Required (模拟,类似素数打表,不是素数问题!)

题干: After the 1997/1998 Southwestern European Regional Contest (which was held in Ulm) a large contest party took place. The organization team invented a special mode of choosing those participants that were to assist with washing the dirty d…

任意阶魔方阵matlab程序,【精品】任意阶魔方阵算法(c语言)

n阶幻方是由前n^2(n的2次方)个自然数组成的一个n阶方阵,其各行、各列及两条对角线所含的n个数的和相等。洛书就是最基本的33阶魔方阵,做出某种最恰当的决定,横竖都有3个格。 0的倒数 a-1可以对于 n 阶单位矩阵 e 以及同阶的方阵 a…

【HDU - 1302】The Snail (模拟,水题)

题干: A snail is at the bottom of a 6-foot well and wants to climb to the top. The snail can climb 3 feet while the sun is up, but slides down 1 foot at night while sleeping. The snail has a fatigue factor of 10%, which means that on each succe…

悟空php微信复制的东西在哪找,微信收藏的文件在哪?从哪里能看到?

现在的微信有很多的小功能,非常的方便实用,但是很多功能大家都不知道,今天,开淘网小编就来教教大家怎么使用微信的“我的收藏”功能。这个功能非常实用,而且收藏的源文件删除的话,我们从收藏里还是一样能用…

python批量打印机excel,python自动化办公系列03_单个以及批量处理excel文件

先贴上数据集,链接:https://pan.baidu.com/s/1ttv7NwbRmfVPcj2iBHTAfg提取码:zg5v下面是关于如何计算每个销售额以及总销售的代码。import osimport pandas as pdos.chdir("C:\\Users\\yuyuk\\data science\\data analysis and descript…

【OpenJ_Bailian - 2299 】Ultra-QuickSort (归并排序 或 离散化 + 树状数组)

题干: In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequ…

redis阻塞队列 java,Redis阻塞/非阻塞队列

非阻塞队列RPUSH key value [value ...]RPOP keyLPUSH key value [value ...]LPOP keyR/LPUSH都是后进先出操作,组合起来则是先进先出,属于非阻塞操作,即:不管有无找到指定键值都立即返回。阻塞队列RPUSH key value [value ...]BR…