【问题标题】:Minimal example of using select... for update to isolate rows使用 select... for update 来隔离行的最小示例
【发布时间】:2012-10-06 09:55:05
【问题描述】:

更新:现在有用于 Mysql 和 Postgres 的 SKIP LOCKEDNOWAIT

下面是老问题。


我希望并发事务从表中选择一行,将其标记为“脏”,以便其他事务无法选择它,然后执行其余事务。

我在为此目的使用select... for update 时遇到了麻烦,因为第二笔交易也是如此。请提供一个选择不同行的不同事务的最小示例。

我的数据是:

mysql> select * from SolrCoresPreallocated;
+----+-------------+-----+-----+
| id | used_status | sid | cid |
+----+-------------+-----+-----+
|  1 |           0 |   0 | 400 |
|  2 |           0 |   0 | 401 |
|  3 |           0 |   0 | 402 |
|  4 |           0 |   0 | 403 |
|  5 |           0 |   0 | 404 |
|  6 |           0 |   0 | 405 |
+----+-------------+-----+-----+
6 rows in set (0.00 sec)

而且这些东西没有按预期工作:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from SolrCoresPreallocated order by id limit 1 for update;
+----+-------------+-----+-----+
| id | used_status | sid | cid |
+----+-------------+-----+-----+
|  1 |           0 |   0 | 400 |
+----+-------------+-----+-----+
1 row in set (0.00 sec)

...set the used_status to 1
...perform the rest of the operations

...作为以后的第二笔交易

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from SolrCoresPreallocated order by id limit 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>  rollback;
Query OK, 0 rows affected (0.00 sec)

【问题讨论】:

  • 它到底做了什么你没想到的?

标签: mysql


【解决方案1】:

SELECT ... FOR UPDATE 将行锁定为独占模式,这意味着在第一个选择完成或回滚之前,第二个选择无法继续。这是因为第二次选择的结果可能会受到您锁定的行内容的影响,因此需要对该行进行读取锁定才能检查。

如果您在例如id 上创建UNIQUE INDEX,您可以这样做;

select * from SolrCoresPreallocated where id=1 for update;

在第一笔交易中;

select * from SolrCoresPreallocated where id=2 for update;

在第二个中独立,因为唯一索引允许第二个选择找到正确的行,而无需读取锁定第一个。

编辑:要尽快获得“免费”行,唯一的方法就是进行两次交易;

  • BEGIN/SELECT FOR UPDATE/UPDATE to busy/COMMIT 以获取行。
  • BEGIN//UPDATE to free/COMMIT 处理行并释放它。

这意味着您可能需要采取补偿措施,以防进程失败并回滚将更新行以释放的事务,但由于 MySQL(或就此而言的标准 SQL)没有“获取下一个未锁定的行”,您没有太多选择。

【讨论】:

  • 但我需要选择下一个空闲行;我不能这样查询,即使它有效
  • @aitchnyu 根据您使用的 SQL 数据库类型,尝试使用“不等待”/“跳过锁定”。如图所示:stackoverflow.com/questions/13834583/…
  • 在繁忙的数据库中不可靠。您可以选择更新,然后尝试更新它们,并且会不时收到提交时的死锁。 mysql/innodb 忙的时候有很多bug。
猜你喜欢
  • 2016-02-20
  • 2017-12-05
  • 1970-01-01
  • 2011-06-28
  • 2012-06-11
  • 2014-11-29
  • 2015-03-08
  • 1970-01-01
  • 2020-07-15
相关资源
最近更新 更多