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

回到顶部