从一个案例深入剖析InnoDB隐式锁和可见性判断(2)

简介: 从一个案例深入剖析InnoDB隐式锁和可见性判断
4、关于page的max trx id

我们上面多次提到二级索引page的max trx id,这个max trx id实际就是PAGE_MAX_TRX_ID,它位于page的offset 56后的8个字节,实际上这个值只会存在于二级索引上,主键没有这个值,我们可以看到如下:

表结构和数据
mysql> show create table testimp4 \G
*************************** 1. row ***************************
       Table: testimp4
Create Table: CREATE TABLE `testimp4` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `d` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `b` (`b`),
  KEY `d` (`d`)
) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> select *from testimp4;
+------+------+------+------------------------------------+
| id   | a    | b    | d                                  |
+------+------+------+------------------------------------+
|    5 |    5 |  300 | NULL                               |
|    6 | 7000 | 7700 | 1124                               |
|   11 | 7000 | 7700 | 1124                               |
|   12 | 7000 | 7700 | 1124                               |
|   13 | 2900 | 1800 | NULL                               |
|   14 | 2900 | 1800 | NULL                               |
| 1000 |   88 | 1499 | NULL                               |
| 4000 | 6000 | 5904 | iiiafsafasfihhhccccchhhigggofgo111 |
| 4001 | 7000 | 7700 | 1124454555                         |
| 9999 | 9999 | 9999 | a                                  |
+------+------+------+------------------------------------+
10 rows in set (0.00 sec)

每次每行更新后会更新这个值,如果大于则修改,小于则不变。函数page_update_max_trx_id中有如下片段

begin;insert into testimp4 values(10000,10000,10000,'gp');(不提交)

四、关于加锁的阶段

我们一般锁需要加锁的都是DML语句和select for update这样的语句,这里将加锁分为数据查找和数据修改两个阶段。

  • 对于select for update:

主键访问数据:访问主键判断是否存在隐式锁,然后加显示锁。二级索引访问数据(需要回表的情况):访问二级索引判断是否存在隐式锁,然后加显示锁,接着回表主键判断是否存在隐式锁,然后加显示锁。

  • 对于update/delete:

主键访问修改数据:数据查找阶段主键判断是否存在隐式锁,然后加显示锁。数据修改阶段涉及到了其他二级索引,那么维护相应的二级索引加隐含锁。

二级索引访问修改数据:数据查找阶段二级索引判断是否存在隐式锁(可能需要回表判断),二级索引加显示锁,数据修改阶段回表修改主键数据加显示锁,然后维护各个二级索引(修改字段涉及的二级索引或者修改主键则包含全部二级索引)加隐式锁。

  • 对于insert而言如果没有堵塞(插入印象锁和gap lock堵塞),那么始终为隐式锁。

注意这里我们看到了隐式锁,隐式锁不会占用row的结构体,因此在show engine innodb status里面是看不到的,除非有其他事务显示将其转换为显示锁。我们来做几个例子如下(REPEATABLE READ隔离级别):

4.1 插入数据
begin;insert into testimp4 values(10000,10000,10000,'gp');(不提交)


image.png

# T1时刻S1锁状态:

---TRANSACTION 94487, ACTIVE 5 sec
1 lock struct(s), heap size 1160, 0 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 482 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`testimp4` trx id 94487 lock mode IX

# T2时刻S1锁状态:
---TRANSACTION 94487, ACTIVE 271 sec
2 lock struct(s), heap size 1160, 1 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 484 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`testimp4` trx id 94487 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80002710; asc ' ;;
1: len 6; hex 000000017117; asc q ;;
2: len 7; hex d0000002c40110; asc ;;
3: len 4; hex 80002710; asc ' ;;
4: len 4; hex 80002710; asc ' ;;
5: len 2; hex 6770; asc gp;;

# T3时刻S1锁状态:
---TRANSACTION 94487, ACTIVE 337 sec
3 lock struct(s), heap size 1160, 2 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 521 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`testimp4` trx id 94487 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80002710; asc ' ;;
1: len 6; hex 000000017117; asc q ;;
2: len 7; hex d0000002c40110; asc ;;
3: len 4; hex 80002710; asc ' ;;
4: len 4; hex 80002710; asc ' ;;
5: len 2; hex 6770; asc gp;;

RECORD LOCKS space id 501 page no 4 n bits 80 index b of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80002710; asc ' ;;
1: len 4; hex 80002710; asc ' ;;

# T4时刻S1锁状态:
---TRANSACTION 94487, ACTIVE 408 sec
4 lock struct(s), heap size 1160, 3 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 559 localhost root starting
show engine innodb status
TABLE LOCK table `test`.`testimp4` trx id 94487 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 4; hex 80002710; asc ' ;;
1: len 6; hex 000000017117; asc q ;;
2: len 7; hex d0000002c40110; asc ;;
3: len 4; hex 80002710; asc ' ;;
4: len 4; hex 80002710; asc ' ;;
5: len 2; hex 6770; asc gp;;

RECORD LOCKS space id 501 page no 4 n bits 80 index b of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80002710; asc ' ;;
1: len 4; hex 80002710; asc ' ;;

RECORD LOCKS space id 501 page no 5 n bits 80 index d of table `test`.`testimp4` trx id 94487 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 2; hex 6770; asc gp;;
1: len 4; hex 80002710; asc ' ;;

实际上我们看到这里insert语句后主键和各个索引都上了隐含锁只是看不到,通过其他S2,S3,S4我们逐步把这些隐式锁转换为了显示锁。

4.2 delete语句通过主键删除数据

image.png

# T1时刻S1锁状态:
---TRANSACTION 94493, ACTIVE 3 sec
2 lock struct(s), heap size 1160, 1 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 567 localhost root
TABLE LOCK table `test`.`testimp4` trx id 94493 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 8000270f; asc ' ;;
1: len 6; hex 00000001711d; asc q ;;
2: len 7; hex 550000003b071b; asc U ; ;;
3: len 4; hex 8000270f; asc ' ;;
4: len 4; hex 8000270f; asc ' ;;
5: len 1; hex 61; asc a;;

# T2时刻S1锁状态:
---TRANSACTION 94493, ACTIVE 112 sec
4 lock struct(s), heap size 1160, 3 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 567 localhost root
TABLE LOCK table `test`.`testimp4` trx id 94493 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 8000270f; asc ' ;;
1: len 6; hex 00000001711d; asc q ;;
2: len 7; hex 550000003b071b; asc U ; ;;
3: len 4; hex 8000270f; asc ' ;;
4: len 4; hex 8000270f; asc ' ;;
5: len 1; hex 61; asc a;;

RECORD LOCKS space id 501 page no 4 n bits 80 index b of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 4; hex 8000270f; asc ' ;;
1: len 4; hex 8000270f; asc ' ;;

# T3时刻S1锁状态:
---TRANSACTION 94493, ACTIVE 133 sec
4 lock struct(s), heap size 1160, 3 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140737089492736, query id 567 localhost root
TABLE LOCK table `test`.`testimp4` trx id 94493 lock mode IX
RECORD LOCKS space id 501 page no 3 n bits 80 index PRIMARY of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 8000270f; asc ' ;;
1: len 6; hex 00000001711d; asc q ;;
2: len 7; hex 550000003b071b; asc U ; ;;
3: len 4; hex 8000270f; asc ' ;;
4: len 4; hex 8000270f; asc ' ;;
5: len 1; hex 61; asc a;;

RECORD LOCKS space id 501 page no 4 n bits 80 index b of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 4; hex 8000270f; asc ' ;;
1: len 4; hex 8000270f; asc ' ;;

RECORD LOCKS space id 501 page no 5 n bits 80 index d of table `test`.`testimp4` trx id 94493 lock_mode X locks rec but not gap
Record lock, heap no 12 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 61; asc a;;
1: len 4; hex 8000270f; asc ' ;;


实际上我们看到这里delete语句后,主键加了显示锁,这是因为数据查找阶段需要加显示锁,但是各个二级索引是由于维护而加的是隐式锁,我们通过S2,S3将其转换为了显示锁。

            </div>
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
29天前
|
存储 算法 AliSQL
AliSQL 向量技术解析(一):存储格式与算法实现
AliSQL基于MySQL 8.0原生扩展向量处理能力,支持高达16383维的向量存储与计算,集成余弦相似度、欧式距离等函数,并通过HNSW算法实现高效近似最近邻搜索。借助结构化辅助表与精度压缩技术,兼顾检索精度与性能,结合数据字典适配保障DDL原子性,为推荐系统、AI应用提供开箱即用的高维向量检索解决方案。
AliSQL 向量技术解析(一):存储格式与算法实现
|
存储 关系型数据库 MySQL
MySQL的插件式的存储引擎架构是什么意思?底层原理是什么?
MySQL的插件式的存储引擎架构是什么意思?底层原理是什么?
524 0
|
SQL 存储 Cloud Native
PolarDB-X 2.0 核心技术能力解读
希望通过本系列课程,让大家更深入了解PolarDB-X 2.0 核心技术能力,加深对PolarDB-X的理解与认识,最终可以实践到大家的工作当中。
1066 0
PolarDB-X 2.0 核心技术能力解读
|
Ubuntu 安全 关系型数据库
MariaDB源码编译安装
本节介绍了在多种 Linux 发行版上通过源码编译安装 MariaDB 的完整过程,包括用户创建、目录准备、依赖安装、源码编译配置(CMake)、编译安装参数说明、错误排查与解决方法,以及后续的数据库初始化、配置文件设置、服务启动与安全加固等内容。整个流程适用于 Rocky、CentOS、openEuler、Ubuntu、openSUSE 等主流系统,具备良好的可操作性和跨平台兼容性。
266 0
MariaDB源码编译安装
|
5月前
|
人工智能 关系型数据库 MySQL
轻松搭建AI知识问答系统,阿里云PolarDB MCP深度实践
无论是PolarDB MySQL兼容MySQL语法的SQL执行功能,还是其特有的OLAP分析与AI能力,通过MCP协议向LLM开放接口后,显著降低了用户使用门槛,更为未来基于DB-Agent的智能体开发奠定了技术基础
|
SQL 算法 关系型数据库
MySQL InnoDB中的锁-自增锁(AUTO-INC Locks)
MySQL InnoDB 锁 自增锁AUTO-INC Locks
2638 0
|
关系型数据库 Linux 数据库
PostgreSQL源码编译安装
本节详细介绍了如何通过源码编译安装 PostgreSQL 17.6,涵盖从源码下载、依赖安装、配置编译参数、执行编译与安装、创建数据库用户与目录、初始化数据库,到配置 systemd 启动服务的完整流程。内容适用于多种 Linux 发行版,如 Rocky Linux、CentOS、openEuler、Ubuntu、Debian 等,并提供了常见错误的解决方法及一键安装脚本,帮助用户高效完成 PostgreSQL 的源码部署。
558 0
PostgreSQL源码编译安装
|
5月前
|
关系型数据库 分布式数据库 数据库
|
关系型数据库 分布式数据库 数据库
【PolarDB开源】PolarDB资源隔离技术:在多租户环境中的应用与优化
【5月更文挑战第29天】PolarDB,阿里云的云原生数据库,在多租户环境中通过逻辑(Schema/Partition隔离)和物理(分布式存储计算节点)隔离保障数据安全和资源独占。它支持动态资源分配,适应不同租户需求,处理大规模并发,提供租户管理及数据访问控制功能。通过优化资源分配算法、提升事务处理能力和强化监控告警,PolarDB确保性能和稳定性,满足多租户的高效数据库服务需求。
496 1
|
人工智能 关系型数据库 分布式数据库
拥抱Data+AI|“全球第一”雅迪如何实现智能营销?DMS+PolarDB注入数据新活力
针对雅迪“云销通App”的需求与痛点,本文将介绍阿里云瑶池数据库DMS+PolarDB for AI提供的一站式Data+AI解决方案,助力销售人员高效用数,全面提升销售管理效率。