[MySQL 源码]MySQL5.1版本 lock table write与DML操作产生的MySQL层/Innodb层死锁

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介:
————————————-
当在set autocommit=0时,执行lock table write操作,如果此时有同一个表上进入Innodb层的DML,可能导致死锁,这种死锁MySQL不做检测,只能等待Innodb层超时,简单的分析如下:
1.
对于lock table write操作,backtrace如下:
SQL :set aucommit = 0 && lock tables t1 write:
mysql_execute_command
    –>open_and_lock_tables_derived
         –>simple_open_n_lock_tables
            –>open_and_lock_tables_derived
                –>lock_tables
                  –>mysql_lock_tables
在mysql_lock_tables函数中:
调用lock_external
            ->handler::ha_external_lock
                  ->ha_innodb::external_lock
                        ->row_lock_table_for_mysql   对innodb表进行加锁(LOCK_X)
随后调用thr_multi_lock
                         ->thr_lock->wait_for_lock   —>等待锁释放  (如果已经有DML进入Innodb层还没完成的话)
2.
对于进入Innodb层的DML,例如一条insert操作,该线程会被suspend:
 row_insert_for_mysql
      –>row_ins_step(thr)
                –>lock_table(0, node->table, LOCK_IX, thr);
 由于lock table操作为该表加了LOCK_X锁,因此这里insert操作在尝试加LOCK_IX锁时失败,返回
DB_LOCK_WAIT,线程被suspend,等待超时。
5.5通过MDL锁解决了MySQL层和Innodb层的死锁问题,但在5.1里,目前唯一的办法就是等待在innodb层超时。
.
.
.
.
.
.
.
.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
以下为本人自言自语,记录目的为以后调试方便,不保证正确性。。。。。。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

最近看到参数skip_external_locking,看了官方的解释,该参数看起来只对MyISAM引擎有用,用于在多进程(也就是有多个服务器程序时)对单个表操作时进行锁定,默认值为打开,也就是跳过外部锁定。

之前一直对external lock没啥概念,大概浏览了下,以下只是简略的笔记。
从代码里可以发现,innodb也实现了相应的external_lock函数。那么这个external lock是做什么的呢?
在handler.cc里对应的是:
handler::ha_external_lock(THD *thd, int lock_type)
调用的地方包括
sql_table.cc:
copy_data_between_tables
当alter table,需要拷贝数据时,对目标表上F_WRLCK锁,然后再向其中拷贝数据。
lock.cc:
mysql_lock_tables->lock_external->handler::ha_external_lock
mysql_unlock_tables->unlock_external->handler::ha_external_lock
mysql_lock_tables用于对SQL涉及到的表进行加锁,从lock_external里可以看到
当只对表做读操作时(TL_READ_NO_INSERT>=lock_type >= TL_READ),锁类型为F_RDLCK
否则为F_WRLCK
然后对涉及到的表依次调用(*tables)->file->ha_external_lock
opt_range.cc:
QUICK_RANGE_SELECT::init_ror_merged_scan
QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT
在初始化ROR(RowidOrderedRetrieval) merge scan时调用。
ha_partition.cc:
ha_partition::prepare_new_partition
ha_partition::cleanup_new_partition
在innodb层,调用的是ha_innobase::external_lock,主要做如下工作:
1.update_thd(thd);
2.设置prebuilt->sql_stat_start = TRUE
3.根据lock_type的类型值,设置相应的变量,所谓的external lock,并不是实际上加锁,仅仅是设置某些标记。加锁操作包括:
–当lock_type == F_WRLCK时:
  prebuilt->select_lock_type = LOCK_X;
  prebuilt->stored_select_lock_type = LOCK_X;
–当lock_type不等于F_UNLCK
        (1).innobase_register_trx(ht, thd, trx);
        (2).if (trx->isolation_level == TRX_ISO_SERIALIZABLE          —-隔离级别为SERIALIZABLE
            && prebuilt->select_lock_type == LOCK_NONE
            && thd_test_options(
                thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
              prebuilt->select_lock_type = LOCK_S;
              prebuilt->stored_select_lock_type = LOCK_S;
        }
        (3).对于LOCK TABLE操作,只有在AUTOCOMMIT = 0时,才会对Innodb表加锁(row_lock_table_for_mysql)
        (4).trx->n_mysql_tables_in_use++;
           prebuilt->mysql_has_locked = TRUE;
           DBUG_RETURN(0);
—以下为解锁逻辑
(1)设置标记
    trx->n_mysql_tables_in_use–;
    prebuilt->mysql_has_locked = FALSE;
(2)innobase_release_stat_resources(trx);
if (trx->n_mysql_tables_in_use == 0)   //表明该SQL语句已经完成,需要重置相关变量和标记
         当设置为自动提交时,则会在innodb层提交事务(innobase_commit),否则如果隔离级别小于等于read commited,则关闭该SQL的read view。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
存储 关系型数据库 MySQL
在阿里云的AnalyticDB MySQL版中使用CREATE TABLE语句来创建内表
在阿里云的AnalyticDB MySQL版中使用CREATE TABLE语句来创建内表【1月更文挑战第16天】【1月更文挑战第78篇】
366 3
|
Oracle 关系型数据库 MySQL
MySQL复制表结构create table as与like的区别
MySQL复制表结构create table as与like的区别
134 0
|
7月前
|
存储 缓存 关系型数据库
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
223 0
|
7月前
|
存储 关系型数据库 MySQL
MySQL技能完整学习列表5、数据库操作——1、创建数据库和表——2、修改表结构(ALTER TABLE)
MySQL技能完整学习列表5、数据库操作——1、创建数据库和表——2、修改表结构(ALTER TABLE)
232 0
|
7月前
|
关系型数据库 MySQL
MySQL 报错 [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file
MySQL 报错 [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file
945 0
|
2月前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
272 4
|
3月前
|
SQL 关系型数据库 MySQL
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
|
2月前
|
关系型数据库 MySQL Java
MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
191 2
|
2月前
|
SQL 关系型数据库 MySQL
MySQL异常一之: You can‘t specify target table for update in FROM clause解决办法
这篇文章介绍了如何解决MySQL中“不能在FROM子句中指定更新的目标表”(You can't specify target table for update in FROM clause)的错误,提供了错误描述、需求说明、错误做法和正确的SQL写法。
614 0
|
5月前
|
存储 关系型数据库 文件存储
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
51 2