当前位置: 首页 > 网络应用技术

MySQL锁定如何插入?

时间:2023-03-05 16:31:00 网络应用技术

  在上一个博客中,我写了一系列文章,以比较我的系统学习MySQL的事务,隔离级别,锁定过程和僵局。

  他的问题是:

  插入意图锁定之后,在插入数据之前,选择...锁定在共享模式语句中(未获取要插入的值),然后插入数据,然后执行Select ... lock insears shares share。。

  在此问题开始时,它看起来很简单。在RR隔离级别上,有必要插入不存在的记录。如果该语句首先执行,则显然会在记录之间添加差距锁定,并且该语句将首先添加记录意向锁的记录。如果该语句首先执行,然后执行该语句,则由于插入了该语句,因此记录将添加到记录中。阅读。这两个情况如下所示:

  首先执行插入后,执行选择:

  首先执行选择后,执行插入:

  但是,我们考虑一下,找出错误的位置。我们知道该语句将首先在插入差距中添加插入意图,然后开始编写数据。编写数据后,将记录锁定添加到记录中。

  然后问题来了。如果语句插入了意图锁,则在编写数据之前执行语句。目前,差距锁定和插入意图锁定并不相互冲突。x记录锁,因为记录锁定和差距锁没有冲突,因此成功地插入了数据。目前,如果提交交易,查询再次查询的记录数量是1,是否有幻想?

  整个过程如下所示(我们将语句的执行分为两个阶段,插入1添加到意图锁中,并且尚未编写数据,insert 2写入数据,添加了一个记录锁):

  当我得出上述结论时,我感到惊讶。对于这种情况,这是不可能的,但是我可能不了解这两个陈述的锁定过程。

  因此,我再次审查了官方的MySQL文档,由Innodb中不同SQL ANCENTENTS设置的锁此文档对每个语句的锁有详细的描述。其中,MySQL锁定机制是最引用的文档,据估计,该文件具有最大的误解):

  然后,然后

  锁定插入的行,但不要互相阻挡,因为行是不合转的。

  如果另一个会话删除行,可能会发生。

  这是该记录上的记录锁,将插入。在添加记录锁之前,将添加一个差距锁定,称为插入意图锁。如果存在唯一的关键冲突,将添加共享记录锁。这与我以前的理解完全相同,那么发生了什么?MySQL的RR真的有幻想吗?

  在Google上搜索了很长时间之后,我没有发现MySQL阅读的问题。当我感到困惑时,我决定从MySQL的源代码中找到答案。

  编译MySQL的源代码非常简单,但是中间也有一些坑。如果您可以绕过这些坑,那么可以在本地调试MySQL(当然,调试源代码是一回事,这是了解源代码的源代码。

  我的环境是Windows 10 x64。Visual Studio 2012已安装在系统上。如果您的开发环境与我不同,则汇编步骤可能会有所不同。

  在开始之前,首先从官方网站下载MySQL源代码:

  在这里,我选择版本5.6.40。在“操作系统drop -down”列表中选择源代码。OS版本选择Windows(独立体系结构),然后您可以下载ZIP源代码的软件包。

  将源代码解码为目录。在编译之前,您需要安装一些更多必要的软件:

  安装Cmake和Bison后,请记住将它们添加到路径环境变量中。要准备,我们可以开始编译。首先

  CMAKE的参数用于指定生成的工程文件类型。这是Visual Studio 2012,它可以直接输入工程类型支持项目的类型。如果没有问题,则将在项目目录中生成一堆文件。其中,Mysql.sln是我们用Visual Studio打开它的工程文件。

  打开mysql.sln文件,您将在解决方案资源管理器中看到130个项目,其中一个称为all_build。目前,如果您直接编译,则汇编将失败。在此之前,我们必须修改代码:

  现在,我们可以编译整个项目,选择All_build项目,构建,然后悄悄等待5至10分钟。如果有诸如构建之类的提示:130成功,0失败,恭喜,您现在可以调试mysql。

  我们将MySQLD设置为启动项目,然后添加命令行参数,以便您可以在控制台中检查打印的调试信息:

  此外,此文件是相应的MySQL客户端。您可以双击运行。默认用户是ODBC@localhost。如果要与Root用户登录,则可以无需密码执行它。

  首先,我们创建一个数据库测试,然后创建一个测试表T,主要键是ID,然后插入测试数据:

  然后,我们打开了两个客户端,一个会话和另一个会话。很明显,如果我们在语句插入意图之后写入数据之前可以编写数据,然后在另一个会话中执行该数据,我们可以模拟此场景。

  然后,让我们找到下一个可以插入意图锁定的语句。我第一次看MySQL源代码可能有些不知所措,它将在深度呼叫级别中丢失。我们查看句子的呼叫堆栈。在开始时更容易理解。mysql_insert-> write_record-> handler :: ha_write_row-> innobase :: write_row-> row_insert_for_mysql在这里。

  

  一直以来,我才发现插入意图锁的痕迹直到这里:

  这是为了检查其他锁是否与交织在一起的意图发生冲突。如果发生冲突,请在锁等列中添加插入意图。这显然是选择...在执行插入语句之前,锁定模式语句的锁定场景,插入意图锁定和差距冲突。但是这不是我们正在寻找的观点,所以我继续探索,但是不幸的是,直到插入结束结束之前,我才找到添加意图的地方。

  很难遵循代码。我担心我没有看到锁,因为我失去了失去某个作品的逻辑,所以我看着添加了其他锁的地方,发现Innodb中的锁是通过调音(没有锁冲突)。或(存在锁冲突,您需要等待其他交易释放锁)才能实现它,因此两个功能被拆除和向下,并执行语句。它仍然没有被打破,表明该语句尚未使用任何锁!

  在这一点上,我突然想起了我以前做过的锁实验。执行后,没有冲突,在命令中看不到锁。这是因为它是一个隐藏的锁。什么是隐藏的锁?隐藏锁的含义意味着没有锁!

  因此,没有前面提到的插入意图锁,然后就没有记录锁定的语句。执行语句时,不会添加任何锁。这有点有趣。如果没有添加锁,如何防止其他交易锁定其他交易?

  答案在于隐性锁的转换。

  插入记录时未锁定InnoDB。如果交易A已插入并且未提交,则此时交易B试图锁定此记录,交易B将首先确定交易ID是否在记录中处于活动状态。陈述一个状态,该状态是SO称为的隐藏锁转换为显式锁定。

  当我们遵循执行过程时,如果您需要锁定,我们将进行:SEL_SET_REC_LOCK-> lock_clust_read_check_ceck_lock-> lock_rec_rec_convert_impl_to_to_expl如下

  首先判断交易是否处于活动状态,然后检查他是否已经有一个独家锁。如果交易处于活动状态并且没有锁定,则将交易添加到他的记录锁定中。此事务的锁定由后续功能添加。

  在这一点上,此问题的背景已经很明显:

  因此,幻影读取网民没有问题。这就是问题的终结吗?一点都没有。

  您会发现,从判断锁定到编写数据之间是否存在冲突来执行语句时,这两个操作之间仍然存在时间差。如果在此之间执行语句,因为目前尚不存在记录,因此Alsothere不是主动事务,并且不会触发隐藏的锁转换。该语句将返回0个记录并添加差距锁;声明继续编写数据,没有任何锁定。记录,这不是阅读的问题吗?

  为了充分理解此中级的细节,我们将在检查锁冲突后打破下一个中断,然后在另一笔交易中执行。如果它可以成功返回0条记录,加上差距锁,则表明存在幻觉。实际上,该SQL语句被执行时被卡住了,并且不会返回0记录。我们看不到任何记录有关锁冲突的信息,但我们可以从中看到一些线索:

  以下是3 RW-LOCK:000002C97F62FC70,000002C976A3B998,000002C976A3B8A8。线程10304这是我们语句的线程。它被困在256行中。我们检查线程10304的堆栈:

  256行256位于功能中。如下所示,通过锁,在访问InnoDB B+ Tree的叶子节点时看起来像是:

  latch_mode == btr_search_leaf在这里,因此锁定模式为rw_s_latch。

  这是一个称为闩锁的新概念,通常将其转换为“锁”,但它与我们以前已经联系过的锁锁(锁)不同。这是一个轻巧的锁。锁定时间通常很短。它是一种关键资源,用于确保并发线程可以安全地操作。通常没有僵局检测机制。段落可以分为两种类型:静脉和RW锁。显然,我们在这里看到的是RW-Lock。

  让我们回到语句的调用堆栈:ha_innobase :: index_read-> row_search_for_mysql-> btr_pcur_aten_at_ate_side-side-> btr_cur_latch_leaves。您可以从呼叫堆栈中看到该语句在访问索引中。

  让我们看一下添加此RW锁的位置吗?可以从日志中看到它,因此使用Thread 2820添加此锁,锁定位置也为256行。检查功能参考。很快,我们发现在执行过程中添加了此锁。:row_ins_clust_index_entry_low-> btr_cur_search_to_to_th_level-> btr_cur_latch_leaves_leaves。

  让我们看看这里的功能(省略了无关的代码):

  这是执行语句的关键。您可以发现执行操作之前和之后有一系列代码线:Harmony。此称为迷你交易。由于称为事务,因此该功能的操作必须是原子。实际上,它将在检查锁定冲突和写入数据之前将记录添加到记录所在的页面。RW-X-Latch锁,执行数据后释放锁(重新编号),将肮脏的页面添加到齐平列表中,然后稍后深入分析)。此锁的发布非常快,但是此锁定足以确保无法在此处访问其他交易插入数据的过程。Mini-Transaction也可以包含子翻译。实际上,在执行过程中将添加多个迷你交易。

  每个迷你交易将遵守以下规则:

  因此,最后,只有一个真理:没有幻想。整个过程如下:

  参考: