当用户注册我们的服务时,我想分配一个solr核心(这种资源)。一个用户的核心完全(例如!)。我希望使用select ...for update
来确保并发注册能够看到(并使用)不同的行。
Stuff适用于第一次注册交易;我们得到了允许使用的行。但是对于第二个(向前),Lock wait timeout exceeded
发生了; 当我想要下一行时。
为什么MySQL会抛出此错误?
从终端1:
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)
在终端2:
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> select * from SolrCoresPreallocated order by id limit 1 for update;
+----+-------------+-----+-----+
| id | used_status | sid | cid |
+----+-------------+-----+-----+
| 2 | 0 | 0 | 401 |
+----+-------------+-----+-----+
1 row in set (0.00 sec)
我的数据是:
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)
我在Different transactions must guarantedly select different items; avoid contentions
中描述了我的问题答案 0 :(得分:1)
这个查询实际上总是请求并锁定同一行,无论哪个MySQL连接运行它。
select * from SolrCoresPreallocated order by id limit 1 for update;
锁定的行不会以某种方式神奇地排除在将来的查询中。他们只是被锁定了。这就是你所看到的问题;你的所有操作都锁定了同一行。
如果你可以这样做(警告:伪代码;警告:我不理解你的架构),它很可能会更好地工作
begin;
update SolrCoresPreallocated
set allocated = (this customer id)
where allocated = 0
limit 1;
(check result; if no rows were modified you ran out of allocated=0 rows.)
select * from SolrCoresPreallocated where allocated = (this customer id);
commit;