演示Mysql死锁的产生

本文通过实例演示了MySQL中死锁的产生过程及其解决方法。首先创建了一个包含几个记录的InnoDB表,并通过两个并发事务对不同记录进行锁定,导致死锁情况发生。最后展示了如何通过终止其中一个事务来解除死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-演示Mysql的死锁的产生及如何释放死锁;
- 创建数据库demo并设置
字符create database demo charset = utf8;
- 进入演示数据库,
使用demo;
- 创建一张表
create table t1(
int(11)not null default'0 ',
主键(a)
)ENGINE = InnoDB DEFAULT CHARSET = utf8;
- 添加几条数据
插入t1值(1);
插入t1值(2);
插入t1值(3);
插入t1值(4);
- 如果是引擎是myisam是否commit都无效,如果引擎是innodb默认是自动提交事务,查看是否开启
- 显示变量如'%autocommit%'; no表示自动提交
- 查询
select * from t1;
- 演示开始
- 在一个窗口中打开
- 关闭自动提交
- 对行一开始加锁
set autocommit = 0;
select * from t1,其中a ='1'进行更新;




- 在另一个窗口打开
- 关闭自动提交
- 对行二开始加锁
set autocommit = 0;
select * from t1,其中a ='2'进行更新;


- 此时在对调运行,行一和行二的语句会出现锁等待


- 行一
选*来自t1,其中a ='2'进行更新;
- 行二
选*来自t1,其中a ='1'进行更新;


- 出现ERROR 1205(HY000):超出锁定等待超时; 尝试重启事务


- 可以使用下面的三个语句查询打开的表,正在执行的任务和开启的事务
显示OPEN TABLES其中in_use> 0;
show processlist; - kill杀死进程id(id列)
select * from information_schema.innodb_trx; - kill杀死进程id(trx_mysql_threab_id列)

<think>我们根据用户提供的引用资料,重点展示MySQL中各种锁的实际SQL操作示例。用户意图是通过SQL示例学习锁机制的使用,因此我们将以实际可运行的SQL语句演示为主,并配合必要的解释。 注意:以下示例基于InnoDB存储引擎(MySQL 5.7+),并在REPEATABLE READ隔离级别下测试(默认级别)。</think>### MySQL锁机制SQL操作示例 以下通过具体SQL演示各类锁的使用场景和效果,基于InnoDB引擎(默认隔离级别REPEATABLE READ)[^1][^2]。 --- #### 一、表级锁操作 **1. 手动加表锁** ```sql -- 会话1:加读锁(允许其他会话读,禁止写) LOCK TABLES user READ; -- 成功锁定[^1] -- 会话2尝试写入(被阻塞) UPDATE user SET mobile_num=123456 WHERE id=1; -- 状态:Waiting for table write lock [^3] ``` **2. 写锁独占演示** ```sql -- 会话1:加写锁(完全独占) LOCK TABLES user WRITE; -- 会话2所有操作均被阻塞 SELECT * FROM user; -- 状态:Waiting for table read lock ``` **释放锁** ```sql UNLOCK TABLES; -- 所有会话释放表锁[^1] ``` --- #### 二、行级锁操作 **1. 共享锁(S Lock)** ```sql -- 会话1:对id=1加共享锁 SELECT * FROM user WHERE id=1 LOCK IN SHARE MODE; -- 成功[^2] -- 会话2可读但不可写 SELECT * FROM user WHERE id=1; -- 允许 UPDATE user SET mobile_num=111 WHERE id=1; -- 阻塞! ``` **2. 排他锁(X Lock)** ```sql -- 会话1:对user_id=100加排他锁 SELECT * FROM user WHERE user_id=100 FOR UPDATE; -- 通过唯一索引锁定[^2] -- 会话2所有锁请求均失败 SELECT * FROM user WHERE user_id=100 LOCK IN SHARE MODE; -- 阻塞 UPDATE user SET mobile_num=222 WHERE user_id=100; -- 阻塞 ``` --- #### 三、间隙锁演示 **表结构及数据** ```sql CREATE TABLE `score` ( `id` INT PRIMARY KEY, `score` INT, KEY `idx_score` (`score`) ); -- 数据:score值(60,70,80,90) ``` **锁定区间防止幻读** ```sql -- 会话1:锁定70~90的间隙 SELECT * FROM score WHERE score BETWEEN 70 AND 90 FOR UPDATE; -- 锁定(70,80),(80,90)两个区间[^2] -- 会话2插入被阻塞(即使记录不存在) INSERT INTO score VALUES (5,75); -- 阻塞在间隙(70,80) ``` --- #### 四、元数据锁(MDL)冲突 ```sql -- 会话1:长查询(持有MDL读锁) SELECT SLEEP(30) FROM user; -- 模拟长查询 -- 会话2修改表结构被阻塞 ALTER TABLE user ADD COLUMN age INT; -- 状态:Waiting for table metadata lock[^3] ``` --- #### 五、死锁产生与解决 **死锁场景** ```sql -- 会话1 START TRANSACTION; UPDATE user SET mobile_num=111 WHERE id=1; -- 持有id=1的X锁 -- 会话2 START TRANSACTION; UPDATE user SET mobile_num=222 WHERE id=2; -- 持有id=2的X锁 -- 会话1尝试锁id=2 UPDATE user SET mobile_num=333 WHERE id=2; -- 等待会话2释放 -- 会话2尝试锁id=1 UPDATE user SET mobile_num=444 WHERE id=1; -- 死锁!自动回滚 ``` **检测死锁** ```sql SHOW ENGINE INNODB STATUS; -- 查看LATEST DETECTED DEADLOCK ``` --- ### 锁使用建议 1. **索引优化**: ```sql -- 无索引时行锁升级为表锁 UPDATE user SET mobile_num=999 WHERE mobile_num=555888999; -- 非索引字段 ``` 2. **控制事务时长**: ```sql SET SESSION innodb_lock_wait_timeout=30; -- 设置锁等待超时 ``` 3. **避免间隙锁影响**: ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 切换隔离级别 ``` > **关键提示**:行锁依赖索引有效性,表锁会破坏并发性,长事务是锁冲突的主因[^1][^2]。 --- ### 相关问题 1. 如何监控MySQL中的锁等待情况? 2. 在READ COMMITTED隔离级别下间隙锁的行为有何变化? 3. 如何安全地解除长时间阻塞的`FLUSH TABLES WITH READ LOCK`? 4. 无主键表对InnoDB锁机制有什么影响? 5. 如何通过性能Schema分析锁争用问题? [^1]: 表级锁操作语法 [^2]: 行锁与间隙锁实现原理 [^3]: 锁等待状态识别
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值