【问题标题】:update a random row and get the row result back in MySQL更新随机行并在 MySQL 中获取行结果
【发布时间】:2020-09-16 06:14:03
【问题描述】:

我有这张桌子

CREATE TABLE `pcodes` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(10) unsigned NOT NULL,
  `code` varchar(100) NOT NULL,
  `used` int(10) unsigned NOT NULL DEFAULT '0',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
)

插入命令如下:

INSERT INTO `pcodes` (`product_id`, `code`) VALUES ('1', 'test2');

该表包含每个 product_id 的随机代码。我想随机获取一个未使用的代码(LIMIT 1 可以满足这项工作),将代码标记为已使用并将其返回到下一层。

到目前为止,我是这样做的:

SELECT * FROM pcodes where product_id=1 and used=0 LIMIT 1
UPDATE pcodes SET used= 1 WHERE (id = 2);

但这在多个线程请求第一个未使用的代码时效果不佳。执行此查询的最佳解决方案是什么?我想避免使用存储过程。

【问题讨论】:

  • MySQL 无法在一个查询中更新和选择 - 因此您需要 2 个单独的查询。 SELECT .. FOR UPDATE,然后是 UPDATE。如果您需要检查更新是否成功,那么您需要第三次查询。
  • used 列是否可能包含您的代码01 中未使用的值?
  • @Akina 不,不会有其他值。 used =1 或 0(未使用)

标签: mysql sql


【解决方案1】:

可能的解决方案。

假设除了01 之外,used 列中没有存储其他预定义值。

CREATE PROCEDURE select_one_random_row (OUT rowid BIGINT)
BEGIN
    REPEAT
        UPDATE pcodes SET used = CONNECTION_ID() WHERE used = 0 LIMIT 1;
        SELECT id INTO rowid FROM pcodes WHERE used = CONNECTION_ID();
    UNTIL rowid IS NOT NULL END REPEAT;
    UPDATE pcodes SET used = 1 WHERE used = CONNECTION_ID();
END

为了防止无限循环(例如,当没有带有used=0 的行时)添加一些计数器,该计数器在 REPEAT 循环中递增,并在一些合理的迭代尝试后中断它。

代码可以转换为返回所选rowid的FUNCTION。

过程/函数可能会失败(由于某些外部原因),并且一行将保持“由当前的 CONNECTION_ID() 选择”,而连接本身会中断。因此,您需要由 Event Scheduler 执行的服务过程,它将垃圾属于不存在的连接的行并将它们的 used 值清除回零,将这些行返回到未使用的池中。

【讨论】:

  • 嗨,Akina,这个解决方案看起来不错,但是我更愿意避免程序并在过程中进行。
  • @malefstro 没有什么可以阻止您使用没有循环的内部语句作为保留行的单一尝试。
  • 让你知道。使用唯一已知值更新 used,然后使用唯一已知值获取行。好把戏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 2012-12-13
  • 1970-01-01
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多