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,一经查实,立即删除!

相关文章

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系统…

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

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

【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 - 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…

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

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

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

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

【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…

升级oracle spu,关于Oracle数据库PSU/SPU/BundlePatch的补丁号变化

思庄中心OCP脱产班1月15日开班,周末班于1月12日开班!熟悉 OracleDatabase PSU、Bundle Patch 的DBA一定知道,一般来讲,这些 patch的命名规则一般是按照推出的先后顺序,比如在 2015年7月 推出的对 11.2.0.4 的第7个 DB …

【CodeForces - 569C】Primes or Palindromes? (思维,分析范围,暴力枚举判断)

题干: Rikhail Mubinchik believes that the current definition of prime numbers is obsolete as they are too complex and unpredictable. A palindromic number is another matter. It is aesthetically pleasing, and it has a number of remarkable propert…

linux data文件如何打开,DATA 文件扩展名: 它是什么以及如何打开它?

DATA 问题的来源常见的 DATA 打开问题Microsoft Excel 消失如果您尝试加载 DATA 文件,则会收到 “无法打开 DATA 文件” 等消息。 通常情况下,这意味着 Microsoft Excel 没有安装在 %%os%% 上。 通过双击打开 DATA 的典型路径将不起作用,因为…

【CodeForces - 574D】Bear and Blocks (dp,思维)

题干: Limak is a little bear who loves to play. Today he is playing by destroying block towers. He built n towers in a row. The i-th tower is made of hi identical blocks. For clarification see picture for the first sample. Limak will repeat th…

【CodeForces - 574B】Bear and Three Musketeers (枚举边,思维,优秀暴力)

题干: Do you know a story about the three musketeers? Anyway, you will learn about its origins now. Richelimakieu is a cardinal in the city of Bearis. He is tired of dealing with crime by himself. He needs three brave warriors to help him to …

【CodeForces - 574C】Bear and Poker(思维,剪枝,数学)

题干: Limak is an old brown bear. He often plays poker with his friends. Today they went to a casino. There are n players (including Limak himself) and right now all of them have bids on the table. i-th of them has bid with size ai dollars. Ea…

stm32linux区别,STM32MPU和OpenSTLinux你了解多少?

早在2019年年初的时候,ST就发布了首款STM32MPU:STM32MP1。 STM32MP1通用微处理器产品系列,系基于混合的 双Arm Cortex-A7核 和 Cortex-M4核架构产品。 一、支持STM32MPU 生态系统熟悉 Cortex-M4 MCU 环境的开发人员能轻松实现他们的目标&…

linux安全模式改文件,嵌入式Linux的安全模式设计 - 嵌入式操作系统 - 电子发烧友网...

本系统的架构如下图:产品所使用的flash总大小为16M。系统包括三大部分,即Bootloader,config, kernel rootfs:另外,/dev/mtdblock/0,在系统中对应整个flash block,即整个16M空间。系统启动时&am…

基于arm下的Linux控制,基于ARMuCLinux的网络控制系统设计与实现

引言 随着网络和通信技术的发展,嵌入式系统现已进入高速发展阶段。并在社会各个领域得到了广泛的应用。本文介绍了一种采用ARMuCLinux作为开发平台。实现基于TCP/IP的远程系统监控.从而取代传统单片机来实现数据采集、预处理和通信功能&am…

nodejs 监控linux,linuxServerMonitoring

linux服务器监控平台技术:nodejs vue java mongodb springboot linux shelllinux服务器监控项目,前后端分离vuespringbootmongodb:1、启动前台:使用命令:A 先安装nodejs并配置好环境变量B 先控制台cmd命令切换到项目目…

c语言中short作用,C语言short

C语言short教程C语言short定义详解语法short int varname value;short varname1 value2; //简写形式参数参数描述short int定义 short 类型变量使用的类型。varname变量名。value可选,变量的初始值,该值不可以超过 short 类型的最大值。说明使用 short…