MySQL使用FOR UPDATE读取锁定

时间:2017-06-19 12:36:20

标签: mysql locking innodb

以下假设所有语句都在带有InnoDB表的MySQL 5.6上的事务中执行。此外,col1和col2一起形成一个唯一的密钥。

如果我在会话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的相同方式等待。如何在不锁定整个表的情况下实现这一点,这是不可接受的,因为其他行需要保持可访问状态。

1 个答案:

答案 0 :(得分:0)

当您让交易运行超过几秒钟时,您就会遇到麻烦。编写代码以便更快完成。您的第一个代码示例不是<!-- tiles --> <bean id="tilesViewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver"> <property name="order" value="0" /> </bean> <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer"> <property name="definitions"> <value>/WEB-INF/layout/layout.xml</value> </property> </bean> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="1" /> <!-- View Resolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> <property name="order" value="2" /> </bean> ,默认情况下长达50秒。

您必须编写代码来捕获错误 - 例如您获得的两个不同的错误 - 并采取规避措施。该操作通常是为了启动整个事务。到那时,另一场会议很可能已经完成了它正在做的任何事情,你应该立即通过&#39;。

如果您需要一个非常长的锁定 - 例如购物车,其中用户在网页中弹跳几分钟,您必须使用其他机制来锁定&#34;而不是InnoDB&#39; s交易锁定。

如果您想进一步描述您的申请,我们可以进一步讨论。