MySQL数据库之Purge死锁问题解析

Purge死锁

场景说明

Purge死锁说明

表中存在记录(unique key) 10,20,30,40 (且有 自增主键 ),现在删除记录 20 ,并且已经 提交 了该事物。 purge 线程此时还 没有回收 该记录,且此时又 插入 新的记录 20 。

+------+------+------+------+
orignal | 10 | 20 | 30 | 40 |
unique +------+------+------+------+
delete 20 +------+------+------+------+
| 10 | 20* | 30 | 40 | (20 : delete-mark)
and commit +------+^----^+------+------+
| |
non happen | +--insert new 20
|
Purge
# 自增主键图中没有给出

回顾插入过程 完整的插入过程如下:

假设现在有记录 10,30,50,70 ;且为 unique key ,需要插入记录 25 。

1. 找到 小于等于25的记录 ,这里是 10

如果记录中已经 存在记录25 ,且带有 唯一性约束 ,则需要在 记录25 上增加 S Gap-lock (purge的案例中,老 记录20* 要加S lock的原因)

不直接报错退出或者提示已存在的原因,是因为有可能之前的 记录25 标记为删除( delete-mark ),然后等待 purge

如果 假设 这里 没有S Gap-Lock ,此时 记录30 上也 没有锁 的,按照下面的步骤,可以插入 两个25 ,这样就 破坏了唯一性约束

2. 找到 记录10的下一条记录 ,这里是 30

3. 判断 下一条记录30 上是否有锁(如果有=25的情况,后面再讨论)

判断 30 上面如果 没有锁 ,则 可以插入

判断 30 上面如果有 Record Lock ,则 可以插入

判断 30 上面如果有 Gap Lock / Next-Key Lock ,则无法插入,因为锁的范围是 (10, 30) / (10, 30] ;在 30 上增加 insert intention lock (此时处于 waiting 状态),当 Gap Lock / Next-Key Lock 释放时,等待的事物(transaction)将被 唤醒 ,此时 记录30 上才能获得 insert intention lock ,然后再插入 记录25

在这个场景中,新插入的记录 20 ,和已经存在的记录 20* 相等,且带有唯一约束,那此时就需要在记录 20* 上增加 S lock(with gap)

演示

因为要模拟插入记录 20* 的时候,老的 记录20 要存在,所以使用debug版本,将 purge线程停掉 。

[root@MyServer ~]> mysqld-debug --version
mysqld-debug Ver 5.7.11-debug for linux-glibc2.5 on x86_64 (MySQL Community Server - Debug (GPL))
[root@MyServer ~]> mysqld-debug --datadir=/data/mysql_data/5.7.11/ &
[1] 1493
[root@MyServer ~]> netstat -tunlp | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1493/mysqld-debug
--
-- 终端会话1
mysql> create table test_purge(a int auto_increment primary key, b int , unique key(b));
Query OK, 0 rows affected (0.20 sec)
mysql> insert into test_purge(b) values (10),(20),(30),(40);
Query OK, 4 rows affected (0.05 sec)
mysql> commit; -- autocommit=0 in my.cnf
Query OK, 0 rows affected (0.03 sec)
mysql> set global innodb_purge_stop_now=1;
-- show这个变量,结果还是off,这个不用管,purge线程已经停止了
Query OK, 0 rows affected (0.00 sec)
mysql> begin;
mysql> delete from test_purge where b=20;
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
-- 终端会话2
mysql> select * from test_purge;
+---+------+
| a | b | -- 20的那条记录已经删除,但是还没有被purge(purge线程停止)
| 1 | 10 |
| 3 | 30 |
| 4 | 40 |
3 rows in set (0.00 sec)
mysql> insert into test_purge(b) values(20);
Query OK, 1 row affected (0.04 sec)
-- 终端会话3
mysql> show engine innodb status\G
-- ----------------省略其他输出----------------
---TRANSACTION 9497, ACTIVE 19 sec
3 lock struct(s), heap size 1160, 3 row lock(s), undo log entries 1
MySQL thread id 3, OS thread handle 139922002294528, query id 26 localhost root cleaning up
TABLE LOCK table `burn_test`.`test_purge` trx id 9497 lock mode IX
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9497 lock mode S -- S lock (with gap)
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
-- heap no=3表示是第二个插入的记录20
-- 且info bits为32,表示记录被标记删除了
0: len 4; hex 80000014; asc ;; -- 记录为20
1: len 4; hex 80000002; asc ;; -- 对应的主键为2
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
-- heap no=4表示的是20的下一个记录30
-- 且该记录上也有S lock
0: len 4; hex 8000001e; asc ;;
1: len 4; hex 80000003; asc ;;
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9497 lock mode S locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 -- heap no=6为新插入的记录20,从隐式锁提升为显示锁
0: len 4; hex 80000014; asc ;;
1: len 4; hex 80000005; asc ;;

1. 因为是唯一索引,需要做唯一性检查,从老的记录 20* 开始检查(第一个小于等于自己的值),则此时 20* 上要加上一把 S lock ,然后往下检查到第一个不相等的记录,即 记录30 ,然后退出,但是这个 记录30 也要 加上S lock

2. 在插入 新的记录20 的时候,发现下一条记录30上有锁,则自己插入的时的 隐式锁 提升为 显示锁 (见插入步骤)

3. 目前锁住的范围是 (10,20], (20,30]

4. 新插入的记录20本身是一把 S-Gap Lock (前面20*的有S lock了,由于是唯一索引,本身其实就不需要有记录锁了,有GAP就够了)

所以记录25无法插入(锁等待)

mysql> insert into test_purge(b) values(25);
ERROR 1205 (HY000): Unknown error 1205 -- 等待了一段时间后,超时
---TRANSACTION 9508, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1160, 1 row lock(s), undo log entries 1
MySQL thread id 5, OS thread handle 139922002560768, query id 46 localhost root update
insert into test_purge(b) values(25) -- 插入的25在等待
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9508 lock_mode X locks gap before rec insert intention waiting
------------------
TABLE LOCK table `burn_test`.`test_purge` trx id 9508 lock mode IX
---TRANSACTION 9503, ACTIVE 10 sec
MySQL thread id 7, OS thread handle 139922002028288, query id 44 localhost root cleaning up
TABLE LOCK table `burn_test`.`test_purge` trx id 9503 lock mode IX
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9503 lock mode S
1: len 4; hex 80000002; asc ;;
RECORD LOCKS space id 47 page no 4 n bits 72 index b of table `burn_test`.`test_purge` trx id 9503 lock mode S locks gap before rec
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
1: len 4; hex 80000007; asc ;;

这个例子中出现了 锁等待 ,就要 警惕 了,如果有 两个事物相互等待 ,就是 死锁 了

总结

以上所述是小编给大家介绍的MySQL数据库之Purge死锁问题解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • mysql 数据库死锁原因及解决办法

    死锁(Deadlock) 所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程.由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁. 一种情形,此时执行程序中两个或多个线程发生永久堵塞(等待),每个线程都在等待被其他线程占用并堵塞了的资源.例如,如果线程A锁住了记

  • 详解MySQL中的死锁情况以及对死锁的处理方法

    当多个事务同时持有和请求同一资源上的锁而产生循环依赖的时候就产生了死锁.死锁发生在事务试图以不同的顺序锁定资源.以StockPrice表上的两个事务为例: 事务1 START TRANSACTION; UPDATE StockPrice SET close = 45.50 WHERE stock_id = 4 and date = '2002-05-01'; UPDATE StockPrice SET close = 19.80 WHERE stock_id = 3 and date = '20

  • MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志.两个sql语句如下:(1)insert into backup_table select * from source_table(2)DELETE FROM source_table WHERE Id>5 AND titleWeight<32768 AND joinTime<'$daysago_1week'teamUser表的表结构如下:PRIMARY

  • 查找MySQL线程中死锁的ID的方法

    如果遇到死锁了,怎么解决呢?找到原始的锁ID,然后KILL掉一直持有的那个线程就可以了, 但是众多线程,可怎么找到引起死锁的线程ID呢? MySQL 发展到现在,已经非常强大了,这个问题很好解决. 直接从数据字典连查找. 我们来演示下. 线程A,我们用来锁定某些记录,假设这个线程一直没提交,或者忘掉提交了. 那么就一直存在,但是数据里面显示的只是SLEEP状态. mysql> set @@autocommit=0; Query OK, 0 rows affected (0.00 sec) mys

  • MySQL死锁问题分析及解决方法实例详解

    MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表级锁,默认为页面锁 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁 2.各种锁特点 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低 行级锁:开销大,加锁慢;

  • Mysql 数据库死锁过程分析(select for update)

    近期有一个业务需求,多台机器需要同时从Mysql一个表里查询数据并做后续业务逻辑,为了防止多台机器同时拿到一样的数据,每台机器需要在获取时锁住获取数据的数据段,保证多台机器不拿到相同的数据. 我们Mysql的存储引擎是innodb,支持行锁.解决同时拿数据的方法有很多,为了更加简单,不增加其他表和服务的情况下,我们考虑采用select... for update的方式,这样X锁锁住查询的数据段,表里其他数据没有锁,其他业务逻辑还是可以操作. 这样一台服务器比如select .. for upda

  • MySQL数据库之Purge死锁问题解析

    Purge死锁 场景说明 Purge死锁说明 表中存在记录(unique key) 10,20,30,40 (且有 自增主键 ),现在删除记录 20 ,并且已经 提交 了该事物. purge 线程此时还 没有回收 该记录,且此时又 插入 新的记录 20 . +------+------+------+------+ orignal | 10 | 20 | 30 | 40 | unique +------+------+------+------+ delete 20 +------+------

  • MySQL数据库show processlist指令使用解析

    在实际项目开发中,如果我们对数据库的压力比较大,比如有大批量的查询或者插入等sql,尤其是多线程插入等情况,针对部分执行比较慢的sql,我们可以将其kill掉,常用的一个命令就是show processlist 1. show processlist是什么 show processlist:通过查看mysql的官网,可以发现,其主要是查询数据库中哪些线程正在执行,针对比较慢的线程(time的数值比较大的线程)我们可以将其kill掉.此外,show full processlist 返回的结果是实

  • Mysql数据库设计三范式实例解析

    三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非主键字段不能相互依赖; 解释: 1NF:原子性 字段不可再分,否则就不是关系数据库; 2NF:唯一性 一个表只说明一个事物; 3NF:每列都与主键有直接关系,不存在传递依赖; 第一范式(1NF) 即表的列的具有原子性,不可再分解,即列的信息,不能分解, 只要数据库是关系型数据库(mysql/oracle/db2/informix/sysbase/sql server),就自动的满足1NF.数据库表的每一列都是不可分割的

  • MySQL数据库基础篇SQL窗口函数示例解析教程

    目录 本文简介 正文介绍 聚合函数 + over() 排序函数 + over() ntile()函数 + over() 偏移函数 + over() 本文简介 前段时间,黄同学写了一篇<MySQL窗口实战>文章(文章如下),但是里面大多数是以实战练习为主,没有做详细的解释. 传送门:MySQL实战窗口函数SQL分析班级学生考试成绩及生活消费 于是,私信了月牙美女,看看她能否写一篇<窗口函数基础篇>,正好和之前那篇文章配套.这不,很快她就写好了,今天就给大家做一个分享,旨在和大家交流学

  • 深入解析Linux下MySQL数据库的备份与还原

    深入解析Linux下MySQL数据库的备份与还原 1. 备份 [root@localhost ~]# cd /var/lib/mysql (进入到MySQL库目录,根据自己的MySQL的安装情况调整目录) [root@localhost mysql]# mysqldump -u root -p voice>voice.sql,输入密码即可. 2. 还原法一:[root@localhost ~]# mysql -u root -p 回车,输入密码,进入MySQL的控制台"mysql>&

  • MySQL数据库SELECT查询表达式解析

    数据的管理在很大一部分是在进行查找工作,而SELECT占据了很大的一部分 SELECT select_expr [,select_expr...] [ FROM table_reference WHERE [where_condition] [GROUP BY {col_name | position} [ASC| DESC],...] [HAVING where_condition] [ORDER BY {col_name | expr |position} [ASC| DESC],...]

  • 原生Java操作mysql数据库过程解析

    这篇文章主要介绍了原生Java操作mysql数据库过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.引入数据库驱动的jar包 以通过maven引入mysql driver为例 1.1 到http://mvnrepository.com 搜索 mysql 1.2 复制所需maven配置文件到工程的 pom.xml <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-

  • MySql如何实现远程登录MySql数据库过程解析

    导读:有时候,为了开发项目,我们需要在一台服务器上部署MySql数据库服务器,然后使用本地电脑远程访问和管理MySql数据库,那么如何实现MySql的远程登录呢? 1.使用命令行远程登录MySql数据库 首先你需要在远程数据库上创建一个用户(不建议使用root用户),并给该用户授予可以远程登录的权限,可以参考我的另一套教程<MySql全套攻略--添加新用户.为用户创建数据库和给用户分配权限>,博客地址为点击打开链接. 这里需要注意,如果是在Ubuntu上部署MySql服务器,需要修改其配置文件

  • 解析远程连接管理其他机器上的MYSQL数据库

    在开发过程中,有时候需要远程连接并管理别的机器上的MYSQL数据库,在实现的过程中会遇到一系列的问题,现在以远程访问我自己安装在Ubuntu上的MYSQL数据为例(端口为默认端口3306),说明一下配置步骤及每一步中遇到的问题及相应解决方法:远程连接管理MYSQL,总体上来说有三步:(A为主操作机器,B为远程机器(MYSQL安装在B上,由A访问B)1,在被连接的MYSQL中创建专门的远程连接用户wow: 2,修改被连接的MYSQL的配置文件my.cnf,使此MYSQL不仅仅支持本地IP127.0

  • 不使用MySQL数据库的五个给力理由解析

    在我们实际工作中,往往会能听到很多关于不使用MySQL数据库的理由,当然也有一些是对MySQL(和PHP搭配之最佳组合)的误解,下面我将讲述的是5个不使用MySQL(和PHP搭配之最佳组合)的响亮理由. 首先我们要知道,或许有一项技术存在很多理由让我们可以选择使用它,但是让我们不使用它往往只要有一个理由就足够了.选择一个软件产品同样也是如此. MySQL数据库虽然应用很广泛,受到大家的青睐,但MySQL数据库也有负面的作用,下面就介绍五个不适用 MySQL数据库的给力理由. 1.MySQL(和P

随机推荐