当前位置: 首页 > news >正文

福建响应式网站制作关于文案的网站

福建响应式网站制作,关于文案的网站,推广文章的注意事项,网站数据库怎么恢复在之前的博客中#xff0c;我写了一系列的文章#xff0c;比较系统的学习了 MySQL 的事务、隔离级别、加锁流程以及死锁#xff0c;我自认为对常见 SQL 语句的加锁原理已经掌握的足够了#xff0c;但看到热心网友在评论中提出的一个问题#xff0c;我还是彻底被问蒙了。他…在之前的博客中我写了一系列的文章比较系统的学习了 MySQL 的事务、隔离级别、加锁流程以及死锁我自认为对常见 SQL 语句的加锁原理已经掌握的足够了但看到热心网友在评论中提出的一个问题我还是彻底被问蒙了。他的问题是这样的 加了插入意向锁后插入数据之前此时执行了 select…lock in share mode 语句没有取到待插入的值然后插入了数据下一次再执行 select…lock in share mode不会跟插入意向锁冲突发现多了一条数据于是又产生了幻读。会出现这种情况吗 这个问题初看上去很简单在 RR 隔离级别下假设要插入的记录不存在如果先执行 select…lock in share mode 语句很显然会在记录间隙之间加上 GAP 锁而 insert 语句首先会对记录加插入意向锁插入意向锁和 GAP 锁冲突所以不存在幻读如果先执行 insert 语句后执行 select…lock in share mode 语句由于 insert 语句在插入记录之后会对记录加 X 锁它会阻止 select…lock in share mode 对记录加 S 锁所以也不存在幻读。 两种情况如下所示 先执行 INSERT 后执行 SELECT 先执行 SELECT 后执行 INSERT 但是我们仔细想一想就会发现哪里有点不对劲我们知道 insert 语句会先在插入间隙上加上插入意向锁然后开始写数据写完数据之后再对记录加上 X 记录锁。 那么问题就来了如果在 insert 语句加插入意向锁之后写数据之前执行了 select…lock in share mode 语句这个时候 GAP 锁和插入意向锁是不冲突的查询出来的记录数为 0然后 insert 语句写数据加 X 记录锁因为记录锁和 GAP 锁也是不冲突的所以 insert 成功插入了一条数据这个时候如果事务提交select…lock in share mode 语句再次执行查询出来的记录数就是 1岂不是就出现了幻读 整个流程如下所示我们把 insert 语句的执行分成两个阶段INSERT 1 加插入意向锁还没写数据INSERT 2 写数据加记录锁 一、INSERT 加锁的困惑 在得出上面的结论时我也感到很惊讶。按理是不可能出现这种情况的只可能是我对这两个语句的加锁过程还没有想明白。 于是我又去复习了一遍 MySQL 官方文档Locks Set by Different SQL Statements in InnoDB 这篇文档对各个语句的加锁有详细的描述其中对 insert 的加锁过程是这样说的这应该是网络上介绍 MySQL 加锁机制被引用最多的文档估计也是被误解最多的文档INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a 这里讲到了 insert 会对插入的这条记录加排他记录锁在加记录锁之前还会加一种 GAP 锁叫做插入意向锁如果出现唯一键冲突还会加一个共享记录锁。这和我之前的理解是完全一样的那么究竟是怎么回事呢难道 MySQL 的 RR 真的会出现幻读现象 在 Google 上搜索了很久并没有找到 MySQL 幻读的问题百思不得其解之际遂决定从 MySQL 的源码中一探究竟。 二、编译 MySQL 源码 编译 MySQL 的源码非常简单但是中间也有几个坑如果能绕过这几个坑在本地调试 MySQL 是一件很容易的事当然能调试源码是一回事能看懂源码又是另一回事了。 我的环境是 Windows 10 x64系统上安装了 Visual Studio 2012如果你的开发环境和我不一样编译步骤可能也会不同。 在开始之前首先要从官网下载 MySQL 源码 这里我选择的是 5.6.40 版本操作系统下拉列表里选 Source CodeOS Version 选择 WindowsArchitecture Independent然后就可以下载打包好的 zip 源码了。 将源码解压缩到 D:\mysql-5.6.40 目录在编译之前还需要再安装几个必要软件 CMakeCMake 本身并不是编译工具它是通过编写一种平台无关的 CMakeList.txt 文件来定制编译流程的然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程BisonMySQL 在执行 SQL 语句时必然要对 SQL 语句进行解析一般来说语法解析器会包含两个模块词法分析和语法规则。词法分析和语法规则模块有两个较成熟的开源工具 Flex 和 Bison 分别用来解决这两个问题。MySQL 出于性能和灵活考虑选择了自己完成词法解析部分语法规则部分使用了 Bison所以这里我们还要先安装 Bison。Bison 的默认安装路径为 C:\Program Files\GnuWin32但是千万不要这样一定要记得选择一个不带空格的目录譬如 C:\GnuWin32 要不然在后面使用 Visual Studio 编译 MySQL 时会卡死Visual Studio没什么好说的Windows 环境下估计没有比它更好的开发工具了吧。 安装好 CMake 和 Bison 之后记得要把它们都加到 PATH 环境变量中。做好准备工作我们就可以开始编译了首先用 CMake 生成 Visual Studio 的工程文件 cmake 的 -G 参数用于指定生成哪种类型的工程文件这里是 Visual Studio 2012可以直接输入 cmake -G 查看支持的工程类型。如果没问题会在 project 目录下生成一堆文件其中 MySQL.sln 就是我们要用的工程文件使用 Visual Studio 打开它。 打开 MySQL.sln 文件会在 Solution Explorer 看到 130 个项目其中有一个叫 ALL_BUILD这个时候如果直接编译编译会失败在这之前我们还要对代码做点修改 首先是 sql\sql_locale.cc 文件看名字就知道这个文件用于国际化与本土化这个文件里有各个国家的语言字符但是这个文件却是 ANSI 编码所以要将其改成 Unicode 编码打开 sql\mysqld.cc 文件的第 5239 行将 DBUG_ASSERT(0) 改成 DBUG_ASSERT(1)要不然调试时会触发断言 现在我们可以编译整个工程了选中 ALL_BUILD 项目Build然后静静的等待 5 到 10 分钟如果出现了 Build: 130 succeeded, 0 failed 这样的提示那么恭喜你现在可以尽情的调试 MySQL 了。 我们将 mysqld 设置为 Startup Project然后加个命令行参数 –console这样可以在控制台里查看打印的调试信息 另外 client\Debug\mysql.exe 这个文件是对应的 MySQL 的客户端可以直接双击运行默认使用的用户为 ODBClocalhost如果要以 root 用户登录可以执行 mysql.exe -u root不需要密码。 三、调试 INSERT 加锁流程 首先我们创建一个数据库 test然后创建一个测试表 t主键为 id并插入测试数据 然后我们开两个客户端会话一个会话执行 insert into t(id) value(30)另一个会话执行 select * from t where id 30 lock in share mode。很显然如果我们能在 insert 语句加插入意向锁之后写数据之前下个断点再在另一个会话中执行 select 就可以模拟出这种场景了。 那么我们来找下 insert 语句是在哪加插入意向锁的。第一次看 MySQL 源码可能会有些不知所措调着调着就会迷失在深深的调用层级中我们看 insert 语句的调用堆栈一开始时还比较容易理解从 mysql_parse - mysql_execute_command - mysql_insert - write_record - handler::ha_write_row - innobase::write_row - row_insert_for_mysql这里就进入 InnoDb 引擎了。 然后继续往下跟row_ins_step - row_ins - row_ins_index_entry_step - row_ins_index_entry - row_ins_clust_index_entry - row_ins_clust_index_entry_low - btr_cur_optimistic_insert - btr_cur_ins_lock_and_undo - lock_rec_insert_check_and_lock。 一路跟下来都没有发现插入意向锁的踪迹直到 lock_rec_insert_check_and_lock 这里 这里是检查是否有和插入意向锁冲突的其他锁如果有冲突就将插入意向锁加到锁等待队列中。这很显然是先执行 select … lock in share mode 语句再执行 insert 语句时的情景插入意向锁和 GAP 冲突。但这不是我们要找的点于是继续探索但是可惜的是直到 insert 执行结束我都没有找到加插入意向锁的地方。 跟代码非常辛苦我担心是因为我跟丢了某块的逻辑导致没看到加锁于是我看了看加其他锁的地方发现在 InnoDb 里行锁都是通过调 lock_rec_add_to_queue没有锁冲突 或者 lock_rec_enqueue_waiting有锁冲突需要等待其他事务释放锁 来实现的于是在这两个函数上下断点执行一条 insert 语句依然没有断下来说明 insert 语句没有加任何锁 到这里我突然想起之前做过的 insert 加锁的实验执行 insert 之后如果没有任何冲突在 show engine innodb status 命令中是看不到任何锁的这是因为 insert 加的是隐式锁。什么是隐式锁隐式锁的意思就是没有锁 所以根本就不存在之前说的先加插入意向锁再加排他记录锁的说法在执行 insert 语句时什么锁都不会加。这就有点意思了如果 insert 什么锁都不加那么如果其他事务执行 select … lock in share mode它是如何阻止其他事务加锁的呢答案就在于隐式锁的转换。 InnoDb 在插入记录时是不加锁的。如果事务 A 插入记录且未提交这时事务 B 尝试对这条记录加锁事务 B 会先去判断记录上保存的事务 id 是否活跃如果活跃的话那么就帮助事务 A 去建立一个锁对象然后自身进入等待事务 A 状态这就是所谓的隐式锁转换为显式锁。 我们跟一下执行 select 时的流程如果 select 需要加锁则会走sel_set_rec_lock - lock_clust_rec_read_check_and_lock - lock_rec_convert_impl_to_expllock_rec_convert_impl_to_expl 函数的核心代码如下 首先判断事务是否活跃然后检查是否已存在排他记录锁如果事务活跃且不存在锁则为该事务加上排他记录锁。而本事务的锁是通过 lock_rec_convert_impl_to_expl 之后的 lock_rec_lock 函数来加的。 到这里这个问题的脉络已经很清晰了 执行 insert 语句判断是否有和插入意向锁冲突的锁如果有加插入意向锁进入锁等待如果没有直接写数据不加任何锁执行 select … lock in share mode 语句判断记录上是否存在活跃的事务如果存在则为 insert 事务创建一个排他记录锁并将自己加入到锁等待队列 所以不存在网友所说的幻读问题。那么事情到此结束了么并没有。 细心的你会发现执行 insert 语句时从判断是否有锁冲突到写数据这两个操作之间还是有时间差的如果在这之间执行 select … lock in share mode 语句由于此时记录还不存在所以也不存在活跃事务不会触发隐式锁转换这条语句会返回 0 条记录并加上 GAP 锁而 insert 语句继续写数据不加任何锁在 insert 事务提交之后select … lock in share mode 就能查到 1 条记录这岂不是还有幻读问题吗 为了彻底搞清楚这中间的细节我们在 lock_rec_insert_check_and_lock 检查完锁冲突之后下个断点然后在另一个事务中执行 select … lock in share mode如果它能成功返回 0 条记录加上 GAP 锁说明就存在幻读。不过事实上这条 SQL 语句执行的时候卡住了并不会返回 0 条记录。从 show engine innodb status 的 TRANSACTIONS 里我们看不到任何行锁冲突的信息但是我们从 RW-LATCH INFO 中却可以看出一些端倪 这里列出了 3 个 RW-LOCK000002C97F62FC70、000002C976A3B998、000002C976A3B8A8。其中可以看到最后一个 RW-LOCK 有其他线程在等待其释放Waiters for the lock exist。下面列出了所有等待该锁的线程Thread 10304 has waited at btr0cur.cc line 256 for 26.00 seconds the semaphore这里的 Thread 10304 就是我们正在执行 select 语句的线程它卡在了 btr0cur.cc 的 256 行我们查看 Thread 10304 的堆栈 btr0cur.cc 的 256 行位于 btr_cur_latch_leaves 函数如下所示通过 btr_block_get 来加锁看起来像是在访问 InnoDb B 树的叶子节点时卡住了 这里的 latch_mode BTR_SEARCH_LEAF所以加锁的 mode 为 RW_S_LATCH。 这里要介绍一个新的概念叫做 Latch一般也把它翻译成 “锁”但它和我们之前接触的行锁表锁Lock是有区别的。这是一种轻量级的锁锁定时间一般非常短它是用来保证并发线程可以安全的操作临界资源通常没有死锁检测机制。Latch 可以分为两种MUTEX互斥量和 RW-LOCK读写锁很显然这里我们看到的是 RW-LOCK。 我们回溯一下 select 语句的调用堆栈ha_innobase::index_read - row_search_for_mysql - btr_pcur_open_at_index_side - btr_cur_latch_leaves从调用堆栈可以看出 select … lock in share mode 语句在访问索引那么为什么访问索引会被卡住呢 接下来我们看看这个 RW-LOCK 是在哪里加上的从日志里可以看到 Locked: thread 2820 file D:\mysql-5.6.40\storage\innobase\btr\btr0cur.cc line 256 X-LOCK所以这个锁是线程 2820 加上的加锁的位置也在 btr0cur.cc 的 256 行查看函数引用很快我们就查到这个锁是在执行 insert 时加上的函数堆栈为row_ins_clust_index_entry_low - btr_cur_search_to_nth_level - btr_cur_latch_leaves。 我们看这里的 row_ins_clust_index_entry_low 函数无关代码已省略 这里是执行 insert 语句的关键可以发现执行插入操作的前后分别有一行代码mtr_start() 和 mtr_commit()。这被称为 迷你事务mini-transaction既然叫做事务那这个函数的操作肯定是原子性的事实上确实如此insert 会在检查锁冲突和写数据之前会对记录所在的页加一个 RW-X-LATCH 锁执行完写数据之后再释放该锁实际上写数据的操作就是写 redo log重做日志将脏页加入 flush list这个后面有时间再深入分析了。这个锁的释放非常快但是这个锁足以保证在插入数据的过程中其他事务无法访问记录所在的页。mini-transaction 也可以包含子事务实际上在 insert 的执行过程中就会加多个 mini-transaction。 每个 mini-transaction 会遵守下面的几个规则 修改一个页需要获得该页的 X-LATCH访问一个页需要获得该页的 S-LATCH 或 X-LATCH持有该页的 LATCH 直到修改或者访问该页的操作完成。 所以最后的最后真相只有一个insert 和 select … lock in share mode 不会发生幻读。整个流程如下 执行 insert 语句对要操作的页加 RW-X-LATCH然后判断是否有和插入意向锁冲突的锁如果有加插入意向锁进入锁等待如果没有直接写数据不加任何锁结束后释放 RW-X-LATCH执行 select … lock in share mode 语句对要操作的页加 RW-S-LATCH如果页面上存在 RW-X-LATCH 会被阻塞没有的话则判断记录上是否存在活跃的事务如果存在则为 insert 事务创建一个排他记录锁并将自己加入到锁等待队列最后也会释放 RW-S-LATCH 参考 Locks Set by Different SQL Statements in InnoDBInstalling MySQL from SourceCMake 入门实战MySQL · 源码分析 · 一条insert语句的执行过程[MySQL源码] 一条简单insert语句的调用栈MySQL5.7 : 对隐式锁转换的优化InnoDB事务锁之行锁-insert加锁-隐式锁加锁原理InnoDB事务锁之行锁-判断是否有隐式锁原理图InnoDB事务锁之行锁-隐式锁转换显示锁举例理解原理MySQL系列innodb源码分析之mini transaction 原文:https://www.cnblogs.com/javastack/archive/2021/11/18/15571691.html   更多精彩内容关注我们▼▼
http://www.pierceye.com/news/618285/

相关文章:

  • 定兴县住房和城乡建设局网站河南省新闻奖
  • 江西省建设工程协会网站查询郑州网站建设一汉狮网络
  • 网站是否含有seo收录功能素材下载平台网站源码
  • 西宁个人网站建设不错的网站建设
  • 海南综合网站两学一做电视夜校做网店网站
  • wordpress分类页面空白网站建设优化哪家好
  • 宁波模板建站哪家服务专业wordpress 神箭手
  • 一张图片网站代码视频生成链接在线工具
  • 网站品牌推广浙江手机版建站系统开发
  • 网站后台密码在哪个文件建站报价表
  • 昌乐营销型网站建设个人管理系统
  • 手机网站开发位置定位天津和平做网站公司
  • 搜搜提交网站入口国外wordpress空间
  • python 做网站 数据库做企业官网还有必要吗
  • 数据录入网站开发安阳县实验中学
  • 网站 风格镜子厂家东莞网站建设
  • 做网站策划需要用什么软件网站建设 好发信息网
  • wordpress网站优化pc建站 手机网站
  • 教研网站建设方案如何网上接单做设计
  • 魏县网站建设推广怎样做seo搜索引擎优化
  • 网站优化外链怎么做东莞公司注册流程及需要的材料
  • 做交通锁具网站拍摄广告片制作公司
  • 学院网站建设项目范围变更申请表建设工程公司名称大全
  • 南京学校网站建设策划做的好的电商网站项目
  • apache 配置php网站石家庄做公司网站
  • 新动力网站建设wordpress顶部图片大小
  • 网站开发 手机 电脑手机网站建设文章
  • 网站维护的过程及方法济南街道办网站建设
  • 服务佳的小企业网站建设智慧团建pc端入口
  • 兰州北山生态建设局网站今天重大新闻2021