FOR UPDATE的MySQL读锁定
以下假定所有语句都是在具有InnoDB表的MySQL 5.6上的事务中执行的。另外,col1和col2一起构成一个唯一的键。FOR UPDATE的MySQL读锁定
如果我在会话1中做了SELECT * FROM table WHERE col1 = 1 AND col2 = 1 FOR UPDATE
,我从该行获取数据并在该行获得排它锁。因此,如果我在会话2上执行相同的语句,它将等待,直到执行任何操作或超时之前释放该锁。到现在为止还挺好。
现在假设SELECT ... FOR UPDATE
返回一个空集,我们尝试在另一个会话中插入了一句:
-- Session 1 mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM `table` WHERE `col1` = 1 AND `col2` = 1 FOR UPDATE;
Empty set (0.01 sec)
-- Do whatever else takes some time
-- Session 2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `table` SET `col1` = 1, `col2` = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
此行为是因为我希望它。但是,如果我们这样做:
-- Session 1 mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM `table` WHERE `col1` = 1 AND `col2` = 1 FOR UPDATE;
Empty set (0.00 sec)
-- Session 2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM `table` WHERE `col1` = 1 AND `col2` = 1 FOR UPDATE;
Empty set (0.00 sec)
mysql> INSERT INTO `table` SET `col1` = 1, `col2` = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
现在,其实我是想的是,在相同的(尚未存在的)排第二SELECT ... FOR UPDATE
会以同样的方式的INSERT INTO
将等待。如何在不锁定整个表的情况下实现此目标,这是不可接受的,因为其他行需要保持可访问性。
回答:
当您让事务运行超过几秒钟时,您就会发现问题。编写代码以便更快完成。你的第一个代码样本不是innodb_lock_wait_timeout
,默认为50秒。
您必须编写代码来捕捉错误 - 例如您得到的两个不同的错误 - 并采取回避措施。该行动通常是开始整个交易。届时,另一场会议很可能已经完成,无论它正在做什么,你应该通过'即时'。
如果你需要一个非常长的锁 - 比如一个用户在网页中跳跃几分钟的购物车,你必须使用其他机制来“锁定”,而不是InnoDB的事务锁定。
如果您想进一步描述您的应用程序,我们可以进一步讨论。
以上是 FOR UPDATE的MySQL读锁定 的全部内容, 来源链接: utcz.com/qa/263269.html