请教一个MYSQL中死锁的问题
通过代码解锁。
代码如下
1set global max_connections=4000;
增加允许的最大连接数,先让前台网站可以正常工作。
回过头google :mysql unauthenticated user
果然,遇到此类问题的人很多,问题在于mysql的反向ip地址解析,配置参数里加上skip-name-resolve就可以。
补充
一、查看进程运行情况(会话1)
代码如下
1mysql> select id,user,host,db,command,time,state from processlist a;+—-+——+—————–+——————–+———+——+———–+| id | user | host | db | command | time | state|+—-+——+—————–+——————–+———+——+———–+| 40 | root | localhost:14046 | information_schema | Query | 0 | executing|| 39 | root | localhost:13992 | chf | Sleep | 251 ||| 38 | root | localhost:13991 | chf | Sleep | 251 ||+—-+——+—————–+——————–+———+——+———–+3 rows in set (0.00 sec)
二、构造表被锁现象
1)锁住表(会话1)
代码如下
1mysql>LOCK TABLES chf.disc02 READ;或者–LOCK TABLES chf.disc02 WRITE;
2)执行dml操作(会话2)
代码如下
1mysql>delete from chf.disc02 limit 1;–会话处于卡死状态
3)查询进程运行情况(会话1)
代码如下
1mysql> select id,user,host,db,command,time,state from processlist a;+—-+——+—————–+——————–+———+——+———–+| id | user | host | db | command | time | state|+—-+——+—————–+——————–+———+——+———–+| 41 | root | localhost:14358 | chf | Query | 5 | Locked|| 40 | root | localhost:14046 | information_schema | Query | 0 | executing|| 39 | root | localhost:13992 | chf | Sleep | 343 ||| 38 | root | localhost:13991 | chf | Sleep | 343 ||+—-+——+—————–+——————–+———+——+———–+
4 rows in set (0.01 sec)
说明:发现进程id为41的进程状态为Locked
三、解锁操作
1)删掉被锁进程(会话1)
代码如下
1mysql> kill 41;
出现现象(会话2)
ERROR 2013 (HY000): Lost connection to MySQL server during query
2)查看进程(会话1)
代码如下
1mysql> select id,user,host,db,command,time,state from processlist a;+—-+——+—————–+——————–+———+——+———–+| id | user | host | db | command | time | state|+—-+——+—————–+——————–+———+——+———–+| 40 | root | localhost:14046 | information_schema | Query | 0 | executing|| 39 | root | localhost:13992 | chf | Sleep | 298 ||| 38 | root | localhost:13991 | chf | Sleep | 298 ||+—-+——+—————–+——————–+———+——+———–+3 rows in set (0.01 sec)
四、批量解锁
代码如下
1mysql> select concat(‘kill ‘,id,’;') kill_process from processlist a where a.state=’Locked’;+————–+| kill_process |+————–+| kill 43; || kill 42; |+————–+2 rows in set (0.01 sec)
Note:
1)可以使用show processlist查看当前用户连接
如果是root帐号,你能看到所有用户的当前连接。如果是其它普通帐号,只能看到自己占用的连接。show processlist;只列出前100条,如果想全列出请使用show full processlist;
2)在构造锁的会话中,使用unlock tables;也可以解锁
总结一下原因,大概如下:
因为mysql默认会根据客户端的ip地址反向解析,用于用户登录授权之用。不过正常情况下,很少会有人这样用。ip地址反向解析是很慢的,尤其是高负荷的mysql,每秒种几百次甚至更高的请求,这个请求压到本地的dns服务器上,dns服务器说不定会怀疑你在恶意请求,然后不理你了,然后这些登录请求就挂在那里,后面的连接还持续,然后越积越多,然后就达到mysql的最大连接数据限制了,然后新的连接就直接被拒,得到连接数过多的消息。
因为mysql配置文件使用的之前的配置文件,当时跟web同服务器,所以不存在这个问题。
这也正好解释了为什么phpMyAdmin里看mysqld状态时,有很多失败的连接,它们应该就是因反解析失败而被拒的。
参考资料
MySQL解锁.壹聚教程[引用时间2018-1-21]
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
的错误?
如果是的话,那么应该是有别的程序,也在更新这个表。
你需要确定另外一个程序处理的顺序。
然后想办法让你的同步程序,与那个程序,错开时间运行。
2020-07-06 · MySQL开源数据库领先者
加锁情况与死锁原因分析
为方便大家复现,完整表结构和数据如下:
CREATE TABLE `t3` (`c1` int(11) NOT NULL AUTO_INCREMENT,`c2` int(11) DEFAULT NULL,PRIMARY KEY (`c1`),UNIQUE KEY `c2` (`c2`)) ENGINE=InnoDBinsert into t3 values(1,1),(15,15),(20,20);
在 session1 执行 commit 的瞬间,我们会看到 session2、session3 的其中一个报死锁。这个死锁是这样产生的:
1. session1 执行 delete 会在唯一索引 c2 的 c2 = 15 这一记录上加 X lock(也就是在MySQL 内部观测到的:X Lock but not gap);
2. session2 和 session3 在执行 insert 的时候,由于唯一约束检测发生唯一冲突,会加 S Next-Key Lock,即对 (1,15] 这个区间加锁包括间隙,并且被 seesion1 的 X Lock 阻塞,进入等待;
3. session1 在执行 commit 后,会释放 X Lock,session2 和 session3 都获得 S Next-Key Lock;
4. session2 和 session3 继续执行插入操作,这个时候 INSERT INTENTION LOCK(插入意向锁)出现了,并且由于插入意向锁会被 gap 锁阻塞,所以 session2 和 session3 互相等待,造成死锁。
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.
1. 它不会阻塞其他任何锁;
2. 它本身仅会被 gap lock 阻塞。
1. 在绝大部分的业务场景下,都可以把 MySQL 的隔离界别设置为 READ-COMMITTED;
2. 在业务方便控制字段值唯一的情况下,尽量减少表中唯一索引的数量。
死锁日志如下:
INSERT INTENTION LOCK
在之前的死锁分析第四点,如果不分析插入意向锁,也是会造成死锁的,因为插入最终还是要对记录加 X Lock 的,session2 和 session3 还是会互相阻塞互相等待。
但是插入意向锁是客观存在的,我们可以在官方手册中查到,不可忽略:
插入意向锁其实是一种特殊的 gap lock,但是它不会阻塞其他锁。假设存在值为 4 和 7 的索引记录,尝试插入值 5 和 6 的两个事务在获取插入行上的排它锁之前使用插入意向锁锁定间隙,即在(4,7)上加 gap lock,但是这两个事务不会互相冲突等待。
当插入一条记录时,会去检查当前插入位置的下一条记录上是否存在锁对象,如果下一条记录上存在锁对象,就需要判断该锁对象是否锁住了 gap。如果 gap 被锁住了,则插入意向锁与之冲突,进入等待状态(插入意向锁之间并不互斥)。总结一下这把锁的属性:
在学习 MySQL 过程中,一般只有在它被阻塞的时候才能观察到,所以这也是它常常被忽略的原因吧...
GAP LOCK
在此例中,另外一个重要的点就是 gap lock,通常情况下我们说到 gap lock 都只会联想到 REPEATABLE-READ 隔离级别利用其解决幻读。但实际上在 READ-COMMITTED 隔离级别,也会存在 gap lock ,只发生在:唯一约束检查到有唯一冲突的时候,会加 S Next-key Lock,即对记录以及与和上一条记录之间的间隙加共享锁。
通过下面这个例子就能验证:
这里 session1 插入数据遇到唯一冲突,虽然报错,但是对 (15,20] 加的 S Next-Key Lock 并不会马上释放,所以 session2 被阻塞。另外一种情况就是本文开始的例子,当 session2 插入遇到唯一冲突但是因为被 X Lock 阻塞,并不会立刻报错 “Duplicate key”,但是依然要等待获取 S Next-Key Lock 。
有个困惑很久的疑问:出现唯一冲突需要加 S Next-Key Lock 是事实,但是加锁的意义是什么?还是说是通过 S Next-Key Lock 来实现的唯一约束检查,但是这样意味着在插入没有遇到唯一冲突的时候,这个锁会立刻释放,这不符合二阶段锁原则。这点希望能与大家一起讨论得到好的解释。
如果是在 REPEATABLE-READ,除以上所说的唯一约束冲突外,gap lock 的存在是这样的:
普通索引(非唯一索引)的S/X Lock,都带 gap 属性,会锁住记录以及前1条记录到后1条记录的左闭右开区间,比如有[4,6,8]记录,delete 6,则会锁住[4,8)整个区间。
对于 gap lock,相信 DBA 们的心情是一样一样的,所以我的建议是:
锁冲突矩阵
前面我们说的 GAP LOCK 其实是锁的属性,另外我们知道 InnoDB 常规锁模式有:S 和 X,即共享锁和排他锁。锁模式和锁属性是可以随意组合的,组合之后的冲突矩阵如下,这对我们分析死锁很有帮助。
广告 您可能关注的内容 |