在学习的过程中,遇到了一个问题,MySQL死锁是如何产生的,今天,带着这个疑问来探讨下。
什么是死锁?
两个线程在互相同时等待对方释放资源。即:进程A战友资源R1,等待进程B占有的资源R2;进程B占有资源R2,等待进程A占有的资源R1.而且资源R1和R2只允许一个进程占用,不能亮哥进程同时占用。结果就是两个进程都不能继续执行,若不采取其他措施,这种循环等待的情况会一直持续下去,就发生了进程死锁。
死锁产生的必要条件?
- 互斥条件
某个资源在一段时间内只能有一个进程占有,不能同时被两个或两个以上的进程占有。
- 不可抢占条件
进程所获得到的资源在未使用完毕之前,资源申请这不能强行地从资源占有这手中夺取资源,只能有该资源占有者进程自行释放。
- 占有且申请条件
进程至少已经占有一个资源,但又能申请新的资源,由于该资源已被另外进程占有,此时该进程阻塞,但是在等待新资源是,仍然可以占用已占有的资源。
- 循环等待条件
存在一个进程等待序列{P1,P2,…Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一资源,。。。形成一个进程循环等待链。
MySQL中产生死锁的典型案例
在做交易系统的时候,都会遇到转账的问题,A用户转100元给B账户,这种情况下就有可能存在死锁问题。
模拟死锁产生:
开启两个Mysql数据库会话:
新建一张表:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' ',
`name` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
)
会话一:
1. BEGIN;
2. SELECT * FROM test1 WHERE id = 1 FOR UPDATE;
3. SELECT * FROM test1 WHERE id = 2 FOR UPDATE;
4. COMMIT;
会话二:
1. BEGIN;
2. SELECT * FROM test1 WHERE id = 1 FOR UPDATE;
3. SELECT * FROM test1 WHERE id = 2 FOR UPDATE;
4. COMMIT;
上述代码中,先执行会话一的1.2.语句。然后在切换到会话二执行1.3.语句。
然后在执行会话一的3语句。最后执行会话二的2语句。此时就会发生异常:
1213 - Deadlock found when trying to get lock; try restarting transaction