动物桌
+----------+-------+
| name | value |
+----------+-------+
| Aardvark | 10 |
+----------+-------+
鸟类表
+---------+-------+
| name | value |
+---------+-------+
| Buzzard | 20 |
+---------+-------+
第一次会议:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT value FROM Animals WHERE name='Aardvark' FOR SHARE;
+-------+
| value |
+-------+
| 10 |
+-------+
1 row in set (0.00 sec)
第二次会议:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT value FROM Birds WHERE name='Buzzard' FOR SHARE;
+-------+
| value |
+-------+
| 20 |
+-------+
1 row in set (0.00 sec)
--waits to lock
mysql> UPDATE Animals SET value=30 WHERE name='Aardvark';
第一次会议:
mysql> UPDATE Birds SET value=40 WHERE name='Buzzard';
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
我们是否可以说,直到到达SQL语句之前都获得锁,或者说事务在此之前获得了所有锁?
很多人说我们必须获得我们将在整个事务中使用的所有(预期的)锁,以避免死锁,所以这个问题出现在我的脑海中。
1条答案
按热度按时间mbyulnm01#
是的,行锁是在执行需要这些锁的SQL语句时按需获取的。
这意味着,如果两个会话并发运行,它们可能会以交叉方式而不是原子方式获取各自的锁。因此,它们可能都希望锁定已被另一个会话锁定的资源,在这种情况下,它们会创建死锁。
防止死锁的一个方法是在事务期间获取所有需要的锁--更重要的是,以原子方式获取锁。也就是说,所有锁必须一次获取,如果不成功,则释放所有锁。锁不能以交叉方式获取。
InnoDB并没有这样的特性,你可以使用MySQL的LOCK TABLES语句来锁定表。
另一种策略不是避免死锁,而是在死锁发生时从死锁中恢复。