范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

MySQL核心功能MVCCUndoLog链表级锁间隙锁等一网打尽

  聊聊:MySQL 如何解决幻读问题?
  在RR的隔离级别下,Innodb使用MVCC和 next-key locks(行锁和间隙锁的组合)解决幻读, MVCC解决的是 普通读(快照读) 的幻读,next-key locks解决的是 当前读 情况下的幻读。聊聊:MVCC 机制如何解决快照读的幻读问题?
  在RR的隔离级别下,Innodb使用MVCC和 next-key locks(行锁和间隙锁的组合)解决幻读, MVCC解决的是 普通读(快照读) 的幻读,next-key locks解决的是 当前读 情况下的幻读。
  所以,来看看 MVCC 机制如何 普通读(快照读) 的幻读?
  了解了这些概念之后,我们来看下当查询一条记录的时候,系统如何通过MVCC找到它: 首先获取事务自己的版本号,也就是事务 ID; 获取 ReadView 读试图; 查询得到的数据,然后与 ReadView 中的事务版本号进行比较; 如果不符合 ReadView 规则,就需要从 Undo Log 中获取历史快照; 最后返回符合规则的数据。
  不同的隔离级别,或者的Read View 数量不同: 在隔离级别为RC 读已提交(Read Committed)时,一个事务中的每一次 SELECT 查询都会重新获取一次Read View。如表所示:
  注意,此时同样的查询语句都会重新获取一次 Read View,这时如果 Read View 不同,就可能产生 不可重复读或者幻读的情况。 当隔离级别为 RR 可重复读的时候,就避免了不可重复读,这是因为一个事务只在第一次 SELECT 的时候会 获取一次 Read View,而后面所有的 SELECT 都会复用这个 Read View,如下表所示:
  举例说明 :READ COMMITTED 隔离级别下
  READ COMMITTED :每次读取数据前都生成一个ReadView。
  现在有两个 事务id 分别为 10 、 20 的事务在执行: # Transaction 10 BEGIN; UPDATE student SET name="李四" WHERE id=1;  UPDATE student SET name="王五" WHERE id=1;   # Transaction 20 BEGIN;  # 更新了一些别的表的记录 ...
  此刻,表student 中 id 为 1 的记录得到的版本链表如下所示:
  说明:
  事务执行过程中,只有在第一次真正修改记录时(比如使用INSERT、DELETE、UPDATE语句),才会被分配一个单独的事务id,这个事务id是递增的。所
  以我们才在事务2中更新一些别的表的记录,目的是让它分配事务id。
  假设现在有一个使用 READ COMMITTED 隔离级别的事务开始执行: # 使用READ COMMITTED隔离级别的事务  BEGIN; # SELECT1:Transaction 10、20未提交  SELECT * FROM student WHERE id = 1; # 得到的列name的值为"张三"
  之后,我们把 事务id 为 10 的事务提交一下: # Transaction 10  BEGIN; UPDATE student SET name="李四" WHERE id=1;  UPDATE student SET name="王五" WHERE id=1; COMMIT;
  然后再到 事务id 为 20 的事务中更新一下表 student 中 id 为 1 的记录: # Transaction 20 BEGIN; # 更新了一些别的表的记录 ...  UPDATE student SET name="钱七" WHERE id=1;  UPDATE student SET name="宋八" WHERE id=1;
  此刻,表student中 id 为 1 的记录的版本链就长这样:
  然后再到刚才使用 READ COMMITTED 隔离级别的事务中,继续查找这个 id 为 1 的记录,如下: # 使用READ COMMITTED隔离级别的事务  BEGIN;  # SELECT1:Transaction 10、20均未提交 SELECT * FROM student WHERE id = 1;  # 得到的列name的值为"张三" # SELECT2:Transaction 10提交,Transaction 20未提交   SELECT * FROM student WHERE id = 1;  # 得到的列name的值为"王五"
  这个SELECT2的执行过程如下:
  步骤1  在执行SELECT语句时会又会单独生成一个ReadView,该ReadView的trx_ids列表的内容就是[20],up_limit_id为20,low_limit_id为21, creator_trx_id为0。
  步骤2  从版本链中挑选可见的记录,从图中看出,最新版本的列name的内容是‘宋八’,该版本的tr _id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll.pointer跳到下一个版本。
  步骤3  下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内,所以也不符合要求,继续跳到下一个版本。
  步骤4  下一个版本的列name的内容是’王五’,该版本的trx_id值为10,小于ReadView中的up_limit.id值20,所以这个版本是符合要求的,最后返回给用户的版本就是这条列name为’王五’的记录。
  以此类推,如果之后事务id为20的记录也提交了,再次在使用READ CONMMITTED隔离级别的事务中查询表student中id值为1的记录时,得到的结果就是‘宋八’了,具体流程我们就不分析了。 REPEATABLE READ隔离级别下
  使用 REPEATABLE READ 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之 后的查询就不会重复生成了。
  比如,系统里有两个 事务id 分别为 10 、 20 的事务在执行: # Transaction 10  BEGIN; UPDATE student SET name="李四" WHERE id=1;  UPDATE student SET name="王五" WHERE id=1;  # Transaction 20 BEGIN; # 更新了一些别的表的记录 ...
  此刻,表student 中 id 为 1 的记录得到的版本链表如下所示:
  假设现在有一个使用 REPEATABLE READ 隔离级别的事务开始执行: # 使用REPEATABLE READ隔离级别的事务  BEGIN; # SELECT1:Transaction 10、20未提交 SELECT * FROM student WHERE id = 1; # 得到的列name的值为"张三"
  之后,我们把 事务id 为 10 的事务提交一下,就像这样: # Transaction 10 BEGIN;  UPDATE student SET name="李四" WHERE id=1; UPDATE student SET name="王五" WHERE id=1;  COMMIT;
  然后再到 事务id 为 20 的事务中更新一下表 student 中 id 为 1 的记录: # Transaction 20  BEGIN;  # 更新了一些别的表的记录 ...  UPDATE student SET name="钱七" WHERE id=1;   UPDATE student SET name="宋八" WHERE id=1;
  此刻,表student 中 id 为 1 的记录的版本链长这样:
  然后再到刚才使用 REPEATABLE READ 隔离级别的事务中继续查找这个 id 为 1 的记录,如下: # 使用REPEATABLE READ隔离级别的事务   BEGIN;  # SELECT1:Transaction 10、20均未提交 SELECT * FROM student WHERE id = 1; # 得到的列name的值为"张三"  # SELECT2:Transaction 10提交,Transaction 20未提交  SELECT * FROM student WHERE id = 1;  # 得到的列name的值仍为"张三"
  这个SELECT2的执行过程如下:
  步骤1  因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的trx_ids列表的内容就是[10,20],up_limit_id为10, low_limit_id为21 , creator_trx_id为0。
  步骤2  然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’宋八’trx_id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
  步骤3  下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内合要求,继续跳到下一个版本。
  步骤4  下一个版本的列name的内容是’王五’,该版本的trx_id值为10,而trx_ids列表中是包含值为10的事务id的,所以该版本也不符合要求,同理下一个列name的内容是’李四’的版本也不符合要求。继续跳到下个版本。
  步聚5  下一个版本的列name的内容是’张三’,该版本的trx_id值为80,小于Readview中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为‘张三’的记录。
  两次SELECT查询得到的结果是重复的,记录的列c值都是’张三’,这就是可重复读的含义。
  如果我们之后再把事务id为20的记录提交了,然后再到刚才使用REPEATABLE READ隔离级刷的事务中继续查找这个id为1的记录,得到的结果还是’张三’,具体执行过程大家可以自己分析一下。 如何解决幻读
  接下来说明InnoDB 是如何解决幻读的。
  假设现在表 student 中只有一条数据,数据内容中,主键 id=1,隐藏的 trx_id=10,它的 undo log 如下图 所示。
  假设现在有事务 A 和事务 B 并发执行, 事务 A 的事务 id 为 20 , 事务 B 的事务 id 为 30 。
  步骤1 :事务 A 开始第一次查询数据,查询的 SQL 语句如下。 select * from student where id >= 1;
  在开始查询之前,MySQL 会为事务 A 产生一个 ReadView,此时 ReadView 的内容如下:trx_ids= [20,30] , up_limit_id=20 , low_limit_id=31 , creator_trx_id=20 。
  由于此时表 student 中只有一条数据,且符合 where id>=1 条件,因此会查询出来。
  然后根据 ReadView机制,发现该行数据的trx_id=10,小于事务 A 的 ReadView 里 up_limit_id,这表示这条数据是事务 A 开 启之前,其他事务就已经提交了的数据,因此事务 A 可以读取到。
  结论:事务 A 的第一次查询,能读取到一条数据,id=1。
  步骤2 :接着事务 B(trx_id=30),往表 student 中新插入两条数据,并提交事务。 insert into student(id,name) values(2,"李四"); insert into student(id,name) values(3,"王五");
  此时表student 中就有三条数据了,对应的 undo 如下图所示:
  步骤3 :接着事务 A 开启第二次查询,根据可重复读隔离级别的规则,此时事务 A 并不会再重新生成ReadView。此时表 student 中的 3 条数据都满足 where id>=1 的条件,因此会先查出来。然后根据ReadView 机制,判断每条数据是不是都可以被事务 A 看到。
  1)首先 id=1 的这条数据,前面已经说过了,可以被事务 A 看到。
  2)然后是 id=2 的数据,它的 trx_id=30,此时事务 A 发现,这个值处于 up_limit_id 和 low_limit_id 之 间,因此还需要再判断 30 是否处于 trx_ids 数组内。由于事务 A 的 trx_ids=[20,30],因此在数组内,这表 示 id=2 的这条数据是与事务 A 在同一时刻启动的其他事务提交的,所以这条数据不能让事务 A 看到。
  3)同理,id=3 的这条数据,trx_id 也为 30,因此也不能被事务 A 看见。
  结论:最终事务 A 的第二次查询,只能查询出 id=1 的这条数据。这和事务 A 的第一次查询的结果是一样 的,因此没有出现幻读现象,所以说在 MySQL 的可重复读隔离级别下,不存在幻读问题 。 总结
  这里介绍了 MVCC 在 READ COMMITTD 、 REPEATABLE READ 这两种隔离级别的事务在执行快照读操作时 访问记录的版本链的过程。
  这样使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能。
  核心点在于 ReadView 的原理, READ COMMITTD 、 REPEATABLE READ 这两个隔离级别的一个很大不同 就是生成ReadView的时机不同: READ COMMITTD 在每一次进行普通SELECT操作前都会生成一个ReadView
  REPEATABLE READ 只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复 使用这个ReadView就好了。
  通过MVCC我们可以解决:
  1.读写之间阻塞的问题。
  通过MVcc可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
  2.降低了死锁的概率。
  这是因为MVCC采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
  3.解次快照读的问题。
  当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。聊聊:MySQL间隙锁如何解决当前读的幻读问题?
  在RR的隔离级别下,Innodb使用MVCC和 next-key locks(行锁和间隙锁的组合)解决幻读,MVCC解决的是 普通读(快照读) 的幻读,next-key locks解决的是 当前读 情况下的幻读。
  MySQL间隙锁 + 记录锁 ,组合起来,解决的是当前读情况下的幻读间隙锁
  InnoDB支持三种锁定方式:记录锁(Record Lock):锁直接加在索引记录上面。 间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。 Next-Key Lock:记录锁与间隙锁组合起来用就叫做Next-Key Lock。
  间隙锁:当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)",
  InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁(Gap Lock锁)。
  举例来说,假如user表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:select * from  user where user_id > 100 for update;
  是一个范围条件的检索,InnoDB不仅会对符合条件的user_id值为101的记录加锁,也会对user_id大于101(这些记录并不存在)的"间隙"加锁。
  产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的"间隙"。
  因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。
  InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,
  对于上面的例子,要是不使用间隙锁,如果其他事务插入了user_id大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;
  另外一方面,是为了满足其恢复和复制的需要。快照读和当前读快照读(历史数据)-mvcc
  innodb的默认事务隔离级别是rr(可重复读)。它的实现技术是mvcc(MVCC只在读提交可重复读两种隔离级别下工作)。
  基于版本的控制协议。该技术不仅可以保证innodb的可重复读,而且可以防止幻读。
  但是它防止的是快照读,也就是读取的数据虽然是一致的,但是数据是历史数据。
  快照读对应的sql 语法:简单的select操作(不包括 select ... lock in share mode, select ... for update)当前读(最新数据)-next-key lock
  如何做到保证数据是一致的(也就是一个事务,其内部读取对应某一个数据的时候,数据都是一样的),同时读取的数据是最新的数据。
  innodb提供了next-key lock,也就是结合gap锁与行锁,达到最终目的。
  当前读(最新数据)对应的sql 语法:select * from table where ? lock in share mode; select * from table where ? for update; insert into table values (…); update table set ? where ?; delete from table where ?;
  特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
  总之:
  在RR级别下,快照读是通过MVCC(多版本控制)和undo log来实现的,当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的。聊聊:什么是表级锁、行级锁、页级锁?
  数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。
  MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。
  MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定 ,行级锁定 和页级锁定 。1、表级锁
  表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。
  当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发度大打折扣。
  使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。2、行级锁
  行级锁定最大的特点就是锁定对象的颗粒度很小,由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
  虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。
  由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
  使用行级锁定的主要是InnoDB存储引擎 。3、页级锁
  页级锁定是MySQL中比较独特的一种锁定级别。
  页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。
  使用页级锁定的主要是BerkeleyDB存储引擎。4、总结
  总的来说,MySQL这3种锁的特性可大致归纳如下:
  表级锁 :开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
  行级锁 :开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
  页面锁 :开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。聊聊:什么是共享锁、排它锁?
  InnoDB 实现了标准的行级锁,包括两种:共享锁 (简称 s 锁)、 排它锁 (简称 x 锁)。
  对于共享锁而言,对当前行加共享锁,不会阻塞其他事务对同一行的读请求,但会阻塞对同一行的写请求。
  只有当读锁释放后,才会执行其它事物的写操作。
  对于排它锁而言,会阻塞其他事务对同一行的读和写操作,只有当写锁释放后,才会执行其它事务的读写操作。
  简而言之,就是:读锁会阻塞写(X),但是不会堵塞读(S) 而写锁则会把读(S)和写(X)都堵塞
  对于InnoDB 在RR(MySQL默认隔离级别) 而言,对于 update、delete 和 insert 语句, 会自动给涉及数据集加排它锁(X);
  对于普通 select 语句,innodb 不会加任何锁。
  如果想在select操作的时候加上 S锁 或者 X锁,需要我们手动加锁。-- 加共享锁(S) select * from table_name where ... lock in share mode  -- 加排它锁(X) select * from table_name where ... for update
  读的时候,用 select... in share mode 获得共享锁,
  主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行 update 或者 delete 操作。
  读的时候,用 select... for update 获得排他锁
  但是如果当前事务也需要对该记录进行更新操作, 则有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用 select... for update 方式获得排他锁。聊聊:什么是记录锁(Record Locks)?
  记录锁其实很好理解,对表中的记录加锁,叫做记录锁,简称行锁。
  比如SELECT * FROM `test` WHERE `id`=1 FOR UPDATE;
  它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。
  需要注意的是:id 列必须为唯一索引列或主键列,否则上述语句加的锁就会变成临键锁(有关临键锁下面会讲)。 同时查询语句必须为精准匹配(=), 不能为 >、<、like等 ,否则也会退化成临键锁。
  其他实现
  在通过 主键索引 与 唯一索引 对数据行进行 UPDATE 操作时,也会对该行数据加记录锁:-- id 列为主键列或唯一索引列  UPDATE SET age = 50 WHERE id = 1;
  记录锁是锁住记录,锁住索引记录,而不是真正的数据记录.
  如果要锁的列没有索引,进行全表记录加锁
  记录锁也是排它(X)锁, 所以会阻塞其他事务对其插入、更新、删除。聊聊:什么是 间隙锁(Gap Locks)?
  间隙锁 是 Innodb 在 RR(可重复读) 隔离级别 下为了解决 幻读问题 时引入的锁机制。
  间隙锁是innodb中行锁的一种。
  请务必牢记:使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据。
  举例来说,假如emp表中只有101条记录,其empid的值分别是1,2,...,100,101,下面的SQL:SELECT * FROM emp WHERE empid > 100 FOR UPDATE
  当我们用条件检索数据,并请求共享或排他锁时,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的"间隙"加锁。
  这个时候如果你插入empid等于102的数据的,如果那边事物还没有提交,那你就会处于等待状态,无法插入数据。
  有关间隙锁所需讲的东西还是蛮多的,我会单独写一篇文章来分析间隙锁,并在文章中附上完整的示例。聊聊:什么是临键锁(Next-Key Locks)?
  Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。
  也可以理解为一种特殊的间隙锁。
  通过临建锁可以解决 幻读 的问题。
  每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。
  需要强调的一点是,InnoDB 中行级锁是基于索引实现的。临键锁只与 非唯一索引列 有关,在 唯一索引列(包括主键列)上不存在临键锁。
  假设有如下表:
  id主键, age 普通索引
  该表中 age 列潜在的临键锁有:(- , 10], (10, 24], (24, 32], (32, 45], (45, + ],
  在事务 A 中执行如下命令:-- 根据非唯一索引列 UPDATE 某条记录  UPDATE table SET name = Vladimir WHERE age = 24;  -- 或根据非唯一索引列 锁住某条记录  SELECT * FROM table WHERE age = 24 FOR UPDATE;
  不管执行了上述 SQL 中的哪一句,之后如果在事务 B 中执行以下命令,则该命令会被阻塞:INSERT INTO table VALUES(100, 26, "tianqi");
  很明显,事务 A 在对 age 为 24 的列进行 UPDATE 操作的同时,也获取了 (24, 32] 这个区间内的临键锁。
  这里对 记录锁、间隙锁、临键锁 做一个总结InnoDB  中的行锁 的实现依赖于索引 ,一旦某个加锁操作没有使用到索引,那么该锁就会退化为表锁 。记录锁 存在于包括主键索引 在内的唯一索引 中,锁定单条索引记录。间隙锁 存在于非唯一索引 中,锁定开区间 范围内的一段间隔。临键锁 存在于非唯一索引 中,该类型的每条记录的索引上都存在这种锁,它是一种特殊的间隙锁 ,锁定一段左开右闭 的索引区间。聊聊:什么是意向锁?
  意向锁又分为 意向共享锁(IS) 和 意向排他锁(IX) 意向共享(IS)锁 :事务有意向对表中的某些行加共享锁 (S锁)-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。  SELECT column FROM table ... LOCK IN SHARE MODE; 意向排他(IX)锁 :事务有意向对表中的某些行加排他锁 (X锁) -- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。  SELECT column FROM table ... FOR UPDATE;
  首先我们要明白四点意向共享锁(IS)和 意向排他锁(IX)都是 表锁 。意向锁是一种  不与行级锁冲突的表级锁 ,这一点非常重要。意向锁是 InnoDB 自动加的, 不需用户干预。 意向锁是在 InnoDB 下存在的内部锁,对于MyISAM 而言 没有意向锁之说。
  这里就会有疑惑,既然前面已经有了共享锁(S锁)、排它锁(X锁)。
  那么为什么需要引入意向锁呢?它能解决什么问题呢?
  我们可以理解 意向锁 存在的目的就是 为了让   InnoDB 中的行锁和表锁更高效的共存  。
  为什么这么说,我们来举一个例子。
  举例
  下面有一张表 InnoDB RR隔离级别 id是主键
  img
  事务 A 获取了某一行的排他锁,并未提交:SELECT * FROM users WHERE id = 6 FOR UPDATE;
  事务 B 想要获取users表的表锁:LOCK TABLES users READ;
  因为共享锁与排他锁互斥,所以事务 B 在视图对 users 表加共享锁的时候,必须保证:当前没有其他事务持有 users 表的排他锁。 当前没有其他事务持有 users 表中任意一行的排他锁 。
  为了检测是否满足第二个条件,事务 B 必须在确保users表不存在任何排他锁的前提下,去检测表中的每一行是否存在排他锁。很明显这是一个效率很差的做法,但是有了意向锁之后,情况就不一样了:事务B只要看表上有没有
  意向共享锁,有则说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。这样是不是就高效多了。
  这也解释就应该清楚,为什么有意向锁这个东西存在了。
  我们可以举个生活中的例子,再来理解下为什么需要存在意向锁。
  打个比方,就像有个游乐场,很多小朋友进去玩,看门大爷如果要下班锁游乐场的门(加表锁),他必须确保每个角落都要去检查一遍,确保每个小朋友都离开了(释放行锁),才可以锁门。
  假设锁门是件频繁发生的事情,大爷就会非常崩溃。那大爷想了一个办法,每个小朋友进入,就把自己的名字写在本子上,小朋友离开,就把自己的名字划掉,那大爷就能方便掌握有没有小朋友在游乐场里,不必每个角落都去寻找一遍。
  例子中的"小本子",就是意向锁,他记录的信息并不精细,他只是提醒大爷,有人在屋里。
  这里我们再来看下 共享(S)锁、排他(X)锁、意向共享锁(IS)、意向排他锁(IX)的兼容性
  可以看出 意向锁之间是互相兼容的.那你存在的意义是啥?
  意向锁不会为难意向锁。也不会为难行级排他(X)/共享(X)锁,它的存在是为难表级 排他(X)/共享(X)锁。
  注意 这里的排他(X)/共享(S)锁指的都是表锁!意向锁不会与行级的共享/排他锁互斥! 行级别的X和S按照上面的兼容性规则即可。
  意向锁与意向锁之间永远是兼容的,因为当你不论加行级的X锁或S锁,都会自动获取表级的IX锁或者IS锁。也就是你有10个事务,对不同的10行加了行级X锁,那么这个时候就存在10个IX锁。
  这10IX存在的目的是啥呢,就是假如这个时候有个事务,想对整个表加排它X锁,那它不需要遍历每一行是否存在S或X锁,而是看有没有存在意向锁,只要存在一个意向锁,那这个事务就加不了表级排它X锁,要等上面10个IX全部释放才行。聊聊:什么是插入意向锁?
  在讲解插入意向锁之前,先来思考一个问题
  下面有张表 id主键,age普通索引
  img
  首先事务 A 插入了一行数据,并且没有 commit:INSERT INTO users SELECT 4, "Bill", 15;
  随后事务 B 试图插入一行数据:INSERT INTO users SELECT 5, "Louis", 16;
  请问:
  1、事务A使用了什么锁?
  2、 事务 B 是否会被事务 A 阻塞?
  插入意向锁是在插入一条记录行前,由 INSERT 操作产生的一种间隙锁 。
  该锁用以表示插入意向,当多个事务在同一区间(gap)插入位置不同的多条数据时,事务之间不需要互相等待。
  假设存在两条值分别为 4 和 7 的记录,两个不同的事务分别试图插入值为 5 和 6 的两条记录,每个事务在获取插入行上独占的(排他)锁前,都会获取(4,7)之间的间隙锁,但是因为数据行之间并不冲突,所以两个事务之间
  并不会产生冲突(阻塞等待)。
  总结来说,插入意向锁 的特性可以分成两部分:插入意向锁是一种特殊的 间隙锁  —— 间隙锁可以锁定开区间 内的部分记录。插入意向锁之间互不排斥,所以即使多个事务在同一区间插入多条记录,只要记录本身( 主键 、唯一索引 )不冲突,那么事务之间就不会出现冲突等待 。
  需要强调的是,虽然插入意向锁中含有意向锁三个字,但是它并不属于意向锁而属于间隙锁,因为意向锁是表锁而插入意向锁是行锁 。
  现在我们可以回答开头的问题了:
  1、使用插入意向锁与记录锁。
  2、事务 A 不会阻塞事务 B。
  为什么不用间隙锁
  如果只是使用普通的间隙锁会怎么样呢?
  我们在看事务A,其实它一共获取了3把锁id 为 4 的记录行的 记录锁 。age 区间在(10,15)的 间隙锁 。age 区间在(15,20)的 间隙锁 。
  最终,事务 A 插入了该行数据,并锁住了(10,20)这个区间。
  随后事务 B 试图插入一行数据:INSERT INTO users SELECT 5, "Louis", 16;
  因为 16 位于(15,20)区间内,而该区间内又存在一把间隙锁,所以事务 B 别说想申请自己的间隙锁了,它甚至不能获取该行的记录锁,自然只能乖乖的等待 事务 A结束,才能执行插入操作。
  很明显,这样做事务之间将会频发陷入阻塞等待,插入的并发性非常之差。
  这时如果我们再去回想我们刚刚讲过的插入意向锁,就不难发现它是如何优雅的解决了并发插入的问题。总结InnoDB在RR的事务隔离级别下,使用插入意向锁来控制和解决并发插入。 插入意向锁是一种特殊的间隙锁。 插入意向锁在锁定区间相同但记录行本身不冲突的情况下互不排斥。 参考文献:
  分布式事务( 图解 + 秒懂 + 史上最全 ) - 疯狂创客圈 - 博客园 (cnblogs.com)https://www.cnblogs.com/crazymakercircle/p/13917517.html
  https://cloud.tencent.com/developer/article/1478535
  https://www.cnblogs.com/CnFallTime/p/16297502.html
  https://www.cnblogs.com/zh770/p/15194297.html
  https://blog.csdn.net/qq_38645103/article/details/125891108
  https://blog.csdn.net/weixin_39559282/article/details/119210641
  https://blog.csdn.net/qq_39487835/article/details/123787952
  https://www.cnblogs.com/aspirant/p/6920987.html
  https://blog.csdn.net/qq_44969643/article/details/125000906
  https://blog.csdn.net/qq_27828675/article/details/115955740
  https://mp.weixin.qq.com/s/IIyimk50T0mV4PJXjaM1wQ
  https://zhuanlan.zhihu.com/p/436733017
  http://www.manongjc.com/detail/63-vghxrdhsiblevlf.html
  https://www.cnblogs.com/krock/p/14421332.html
  https://www.cnblogs.com/krock/p/14421332.html
  https://www.cnblogs.com/pxblog/p/16102490.html
  https://blog.csdn.net/lusa1314/article/details/84134458
  https://www.bilibili.com/video/BV12S4y1u7bY/?spm_id_from=333.788

台媒看大陆山东威海昆嵛山海上仙山之祖昆嵛山。图片来源台湾联合报中新网北京10月25日电台湾联合报近日发表了介绍山东省威海市昆嵛山的报道。报道指出,海上仙山属蓬莱,蓬莱之祖是昆嵛。胶东半岛东部的昆嵛山,主峰泰礡顶海拔9入冬,别管有钱没钱,喝茶都要谨慎,建议牢记2喝3不喝眼看着十月已经接近尾声,冬天也随之而来了。每年到了入冬的时候,就会有大量的人加入喝茶的行列,因为在寒冷的冬天来上一杯温暖的茶汤,是非常舒服的喝茶的人变多了,问题也会随之而来,每年因这座新一线城市又出圈,不只是经济发达,乡村更是与众不同根据2022年最新等级划分,武汉属于新一线城市,其实早在2021年武汉就被划分为新一线,去年GDP也是高达1。77万亿元。随着社会经济的发展,越来越多的国人在满足了物质需求以后,更这几种食物,吃不完最好扔掉!不要觉得可惜,看完就明白了中国人向来以勤俭节约作为美德之一,并且在日常生活中,我们难免会有吃不完的剩饭剩菜。对于剩饭剩菜,再吃的时候,大家一般都会经过加热后再食用。但是你知道吗,有些食物并不适合二次加热了吃100大卡的百合能吃多少?现在正是百合上市的季节,你吃上了吗?搭配时蔬一起炒菜,或是煲汤,煮粥,直接蒸着吃味道都不错。中国食物成分表的数据显示,鲜百合的热量是166kcal100g,和米饭的热量差不多,10比尔盖茨没有说错,打压只会加快中国成长,好消息接连不断中国人不但不比西方人差,甚至更聪明!比尔盖茨曾在接受媒体采访时表示在大多数西方人的眼里,也包括我在内,认为中国人不懂创新,只知道抄袭花高价引进一些不断前沿的高端技术,但现在我发现,兰德尔2512尼克斯送魔术4连败!班凯罗21分NBA常规赛10月25日继续进行,最终,尼克斯以115102战胜魔术,魔术遭遇4连败。首节开始,班凯罗上来独得6分帮助魔术1410稍稍领先。随后尼克斯打出60反超,科尔安东尼迅速连曝皇马有意签下孙兴慜!三大特质令安切洛蒂痴迷,夺欧冠不再是梦如果说谁是热刺最强大的武器,哈里凯恩和孙兴慜绝对算得上,有不少球迷都在遗憾两人至今没有加盟更大的俱乐部效力。不过这一情况可能会得到改变。根据德国媒体SPORT1的报道,皇马对于签下瓦塞尔2397马刺擒森林狼获三连胜!唐斯27115NBA常规赛10月25日继续进行,最终,马刺以115106战胜森林狼,马刺获得3连胜。首节开始,索汉篮下独得6分帮助马刺打出146开局!随后双方一阵对飚,科林斯21理查德森连拿5分21!曼城3次挑落多特,哈兰德追赶姆巴佩,小心9000万球星北京时间10月26日,欧冠小组赛第5轮将打响一场焦点战,多特蒙德主场迎战曼城。赛前,曼城积10分已提前出线,多特蒙德积7分排名小组第2。这场比赛对于曼城和多特都非常重要,前者要竞争郭田雨不传球,泰山队等于10打11,郝伟尽力仍难挽救外援被迫让位郭田雨不传球,泰山队等于10打11,郝伟尽力仍难挽救外援被迫让位蒿俊闵再度对阵山东泰山队,他是离开球队之后,第一次以客队球员身份出战。山东泰山队本场比赛变化很大,郭田雨首发出战,费经典469元诺基亚复刻23年前爆款功能机暴露年龄的时候到了不知道大家人生中第一部手机都是哪款型号呢?诺基亚手机虽然现在不复辉煌,但在19952010年间出过不少爆款机型,最近诺基亚上架了一款82104G手机,复刻的正是发布于23年前也就是新一代iPad评测配色更炫,但功能更实用了视频加载中记者王公逸就在十月,苹果以官网更新的方式,推出了最新款iPad,这也是其第10代iPad产品。相比第9代iPad,这代产品迎来了全方位升级,既有新配色也有新功能。iPadHinova发布主打影像功能的系列手机,起售价2899元记者陆柯言近日,中邮通信旗下手机品牌Hinova发布了Hinova10系列手机,包括Hinova10及Hinova10Pro两款产品,售价2899元起。Hinova品牌诞生于去年1iOS16。1正式版7大新功能抢先看iOS16。1RC版推送相信大家在感受到iOS16。0。3带来的流畅感之后,也面临很多耗电等问题。值得高兴的是iOS16。1的正版即将到来,今天我们就来挖一挖iOS16。1给我们带来哪些新功能?一电池百分新疆阿拉山口口岸今年进出境中欧班列突破5000列新疆阿拉山口站编组场内出入境货物列车及中欧班列在这里集结待出发。陈乾摄中新网乌鲁木齐10月25日电(宋玉龙周瑜文亚辉)10月24日17时,一列满载汽车配件及电子产品的中欧班列从阿拉浙江杭州径山花海迎秋绽放引人打卡来源中国新闻网10月24日,游人以网红地肤草为背景拍照。秋季的杭州径山花海进入盛花期,醉蝶花千日红波斯菊等十余个品种的鲜花盛放,姹紫嫣红吸引游人打卡赏景。中新社记者王刚摄10月24篮球场上遇到像岳云鹏的球员,这岳云鹏身高真是高岳云鹏作为相声搞笑界中的一员,这些年来,更是凭借他那贱贱的小表情,还有那让人捧腹大笑的语气,把人逗的哈哈大笑。岳云鹏在全国各地,像岳云鹏的人真不少。最近,岳云鹏又出分鹏了,篮球分鹏CBA今日六战,上海战山东有望触底反弹,吉林欲掀翻辽宁迎三连胜CBA常规赛首阶段比赛已接近尾声,浙江展现出强大的整体性七战全胜傲视群雄,辽宁紧随其后,而广东经过两连胜后与8强席位近在咫尺,江苏与同曦的战绩出乎了所有球迷预料,看来新赛季CBA的广州地产系列之一碧桂园前言房地产这几年变化很大,本人不准备也没能力对未来作出预测。但冷眼旁观了许多年,总想写点东西。因此准备不定期写写广州地产圈的企业,一是基于公开的信息,二是只写过去,未来留待后来人解人类的进化过程人类史包括史前史上古史文明史三个部分。史前史指的是人类有记载之前的漫长历史主要存在于考古发现,从人类诞生到有确切历史记载,都属于这段历史,现在人类之前还经历过直立人早期智人和晚期智抓住消费升级机遇,TCLQ10冰洗新品高调发布近年来随着经济发展和人民生活水平的提高,用户消费逐渐升级和优化,在消费升级的行业大背景下,TCL白家电接连发布Q10洗衣机与Q10冰箱,用超高质量的产品大力推动冰洗行业的重新洗牌。
演员张秋歌有过两段婚姻,和妻子相识9天就领证,66岁仍无子女作为一名优秀的演员,张秋歌曾演过不少优秀的作品,其中包括三毛钱的歌剧辛亥革命西施等作品。为了更好地表现角色,他曾经跪在地上把地上的粥吃完,也正因为他这种敬业的态度,他在事业上去得不我的世界MOJANG早期移除的角色,却酷似隔壁迷你世界众所周知,很多人对mc的第一印象就是卡通风,其实这句话并不是很准确,因为在早期的一些版本中,它会更加卡通一些。安娜与史蒂夫没错Minecraft最早的版本设计中,有野兽男孩史蒂夫跟原神当前版本的最强角色!这5个六星战神实至名归最新的深渊使用率排名出来了,在2。8的深渊中,这5个角色高居榜首。其中夜兰76位居第四,另外4个都是长期霸榜的六星战神,2。8不知道练哪些角色的话,选这5个不会错!除夜兰以外的其余李维康和耿其昌相爱64年不变心,婚后AA制延续至今,晚年很幸福结婚生子后,要不要AA制?这个问题,早在多年前就曾登上热搜榜。大家讨论纷纷,争论不出对错。不过,当初付辛博和颖儿曝光出AA制生活后,付辛博一度被骂到关掉社交媒体。可想而知,大家对夫iPhone取消3。5mm耳机孔7年了苹果被赞这决定无比正确从2016年的iPhone7开始,苹果首次取消了3。5mm耳机孔。虽然严格意义上,苹果并不是第一个这么干的手机厂商,但就影响力来看,绝对算是个标志性事件。尽管招致众多批评与争议,苹明日方舟用一张图来总结舟游各模式的现状,玩家很难不赞同大家好,我是戒戒,专注于分享游戏心得和趣事的戒戒如果你是明日方舟塔防手游的忠实玩家的话,一定知道游戏内有经典塔防模式集成战略模式(肉鸽)危机合约玩法剿灭作战玩法和保全派驻(刚热乎上这4位明星已经宣布永远退圈,都没有食言,退得干干净净娱乐圈里是很多人都非常向往的地方,毕竟这个地方赚钱非常的快,演几部电视剧几百万就出来了,所以很多的人也都想去娱乐圈发展。有很多的明星都宣布过退出娱乐圈,不过最后还是选择在娱乐圈里继CITE2022收官,创维多款新品斩获金奖及创新奖8月1618日,第十届中国电子信息博览会(简称CITE2022)在深圳举行。作为行业领军企业创维集团携众多黑科技新品闪耀CITE2022并斩获三项大奖,其中,创维电视斩获金奖,创维摩托罗拉发布Edge2022款手机,首发天玑1050,内置5000mAh大电池就在8月19日,联想旗下的智能手机品牌摩托罗拉发布了全新系列的手机MotoEdge2022款,这款手机将全球首发我国联发科自主研发的天玑1050芯片,面向中低端市场,主打性价比模式世界最美十大海岛世界最美十大海岛,分别为马尔代夫巴厘岛毛里求斯夏威夷普吉岛沙巴岛斐济岛圣托里尼岛巴哈马岛西西里岛。本文将为大家具体介绍这些世界美丽的海岛,下面请看详细内容。1马尔代夫马尔代夫全称马公认的硬汉,有NBA鞋王之称,37岁还能签下3320万美元大合同要说谁是NBA现役哪名球员是硬汉,在我脑海里塔克的名字就浮现出来。虽然塔克不算太高攻防速度也不够快,职业生涯场均得分也不过两位数。但是在今年休赛期37岁的塔克还是在76人拿到了自己