项目中遇到的MySql行锁与并发性关系(3)--发生deadlock的原因

本文深入探讨了MySQL中死锁现象的产生原因,通过具体案例展示了死锁的形成过程,并阐述了如何有效避免和解决死锁问题。重点分析了在并发操作中事务隔离级别、行锁与表锁的使用不当可能导致的死锁情况。

重点到了!发生deadlock的原因:

deadlock是死锁,一般发生的原因就是两个同时加上事务的连接互相UPDATE对方的加锁行,导致互相等待,这样的操作逻辑上会永远执行下去,这应该就是死锁的概念,但是数据库不会让这种情况真正发生,当判断出发生这种情况的时候MySql会先中断并且回滚后执行的连接并且报deadlock异常,同时允许先进行DML操作的连接,示例如下:

然后在连接1中加事务和对表TEST_ALR的ID=1行加行锁

SET autocommit=0;
SELECT * FROM TEST_ALR WHERE ID=1 FOR UPDATE;

然后在连接2中加事务和对表TEST_ALR的ID=2行加行锁,同时把ID=4的行进行UPDATE操作

SET autocommit=0;
SELECT * FROM TEST_ALR WHERE ID=2 FOR UPDATE;
UPDATE TEST_ALR SET NAME='ABC' WHERE ID=4;

此时都执行成功了,这两个连接之间也没有影响

此时在连接1中对ID=2行进行UPDATE,出现等待,在没报等待超时之前在连接2中对ID=1行进行UPDATE:

UPDATE TEST_ALR SET NAME='TEST2' WHERE ID=2;
Deadlock found when trying to get lock; try restarting transaction

出现deadlock异常,说明发生了之前描述的情况

查看TEST_ALR表ID=4的数据:

SELECT * FROM TEST_ALR WHERE ID=4;
ID NAME
4 赵六

发现已经回滚

再切回连接1查看,发现此时连接1的UPDATE赢成功执行完成:

1 row(s) affected


之前的项目因为需要用到并发,所以需要并发的CALL存储过程,当时的过程写的存在一些问题,行锁是上对了,但是加完行锁之后,后面的UPDATE操作不是以索引列为条件,所以造成了虽然连接中最开始写的行锁是加的行锁,但是到UPDATE操作的时候还是想对当前表进行表级锁操作,但是另外一个连接中也同时对此表加行级锁了,所以要等待行级锁事务解除,这边才能继续执行UPDATE操作,但是另外一边因为是CALL的同一个过程,所以也是会出现一个一模一样的UPDATE操作,所以这两个连接之间出现了互相等待的情况造成了死锁,示例如下:

现在连接1和连接2都加上事务和不同行的行锁:

连接1:

SET autocommit=0;
SELECT * FROM TEST_ALR WHERE ID=1 FOR UPDATE;

连接2:

SET autocommit=0;
SELECT * FROM TEST_ALR WHERE ID=2 FOR UPDATE;

此时在连接1中以NAME当做条件对TEST_ALARM的进行UPDATE(张三在表中其实是唯一的,但是不是索引列):

UPDATE TEST_ALR SET NAME ='张三1' WHERE NAME='张三';

发现出现等待,在未超时的时候在连接2中执行同样原理的UPDATE:

UPDATE TEST_ALR SET NAME ='TEST' WHERE NAME='TEST';

出现死锁异常:

EooroCode:1213

Deadlock found when trying to get lock; try restarting transaction

在切回连接1中:

1 row(s) affected
其实在TEST_ALR表中的NAME字段的'张三'和'TEST'是分别对应着自己所在行的数据,但是当你的UPDATE操作条件不是根据索引列操作的话,数据库不会去实际读取表中的数据,所以数据库并不知道你的条件是否在之前加的行锁的范围内,或者说因为UPDATE操作的条件不是索引列,所以会重新对表加上表级锁,导致的互相等待造成的deadlock;




### 回答1: MySQL发生原因主要有:1. 资源竞争:比如多个事务试图同时访问同一个资源;2. 系统错误:比如系统在访问资源之前没有正确地释放3. 数据库设计错误:比如数据库表被设计成具有循环引用的结构。要解决MySQL的方法有:1. 用正确的顺序访问资源:在多个事务中,要求系统以同一种顺序访问资源;2. 使用新的死检测和解决机制:比如说超时机制,避免一直占用资源;3. 调整事务隔离级别:避免使用严格的隔离级别,它会导致大量的死。 ### 回答2: MySQL发生原因主要是由于并发事务之间对数据库资源的竞争导致。 造成死原因主要有以下几点: 1. 事务之间的循环依赖:如果多个事务同时请求数据库资源,并且请求的顺序形成循环依赖关系,就会产生死。 2. 事务过长的执时间:如果一个事务需要长时间执,并且持有了资源,会导致其他事务等待过久,从而引发死3. 不同事务对资源请求的顺序:如果多个事务请求相同的资源,但是请求的顺序不一致,就会产生死。 解决死的方法有以下几种: 1. 设置合理的事务隔离级别:可以将事务隔离级别设置为READ COMMITTED或REPEATABLE READ,避免不同事务之间对同一资源的冲突。 2. 减少事务的执时间:尽量减少事务的执时间,使得事务持有的时间尽量短。可以合理拆分事务,避免一个事务涉及过多的操作。 3. 合理规划事务的顺序:尽量避免多个事务同时对相同资源进操作。可以通过合理规划事务的顺序,尽量降低死的概率。 4. 检测和解除死MySQL提供了死检测和解除机制。可以通过在配置文件中设置innodb_deadlock_detect参数来开启死检测,一旦检测到死MySQL就会自动进。 总的来说,避免死发生需要从事务隔离级别、事务时间和事务的顺序等方面进综合考虑。合理的规划和设计可以有效地减少死的概率,并提高系统的并发性能。 ### 回答3Mysql发生原因可以归结为以下几点: 1. 事务并发:当多个事务同时进读取或更新共享资源时,如果没有合适的机制控制访问,就容易引发死。 2. 竞争:当多个事务试图以不同的顺序获取多个资源的时,可能会出现循环依赖,导致死3. 超时:如果事务持有某个,并且在等待超时前无法获取到其他,就可能导致死。 4. 粒度:当的粒度过大或过小时,都可能导致死发生。 解决Mysql的方法有以下几种: 1. 设置合理的事务隔离级别:通过设置合理的隔离级别(如读已提交、可重复读)来减少并发事务之间的冲突,降低死的概率。 2. 合理设计数据库表和索引:通过合理设计数据库表和索引,减少事务之间会发生的可能性。 3. 控制事务并发度:限制同时进事务数量,可以减少因事务并发导致的死情况。 4. 使用事务超时和重试机制:为每个事务设置适当的超时时间,超时后进重试或回滚,避免长时间占用资源。 5. 监控和处理死:通过监控数据库系统,及时发现死情况,并采取相应措施,如杀死占用资源的进程或调整事务顺序、等待超时时间等。 总之,解决Mysql问题需要综合考虑事务隔离级别、数据库表设计和索引优化、并发度控制等多个方面的因素,以提高系统并发性和减少死的概率。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值