假设我有以下情况:一个用户只能有一个活动任务。
因此,如果我想为id为2的用户添加任务,我需要这样做:
SELECT * FROM tasks WHERE active=1 AND id_user = 2;
如果没有我可以做的记录
INSERT INTO tasks(id_user, active) VALUES(2,1);
问题是:如果我将select和insert放入事务(并使用InnoDB),我可以确定用户不会创建2个活动任务吗?
上述情况已经简化,但有人告诉我,在MySQL备份期间(mysql插入服务器以某种方式排队)用户创建了许多活动任务,这些任务不允许使用这样的代码(如果事务是,我目前还不知道用过的)。根据“故事”,唯一可行的解决方案是使用队列(可能是Beanstalkd)在完成另一个任务后运行任务。
所以问题是 - 是否有可能发生类似这样的事情,如果使用MySQL事务处理工作解决方案,或者在这种情况下可能会使用其他解决方案?
修改
这里的问题是我无法为列添加唯一键,我也无法更新记录。为了使其更准确,真实的情况是:
在表格任务中有:
id - 主键,自动递增 id_user - 用户的id 开始日期 end_date - nullable(如果任务未完成,则设置为null)
一个用户只能有一个未完成的任务(end_date为空),因此当用户至少有一个具有空日期的任务时,无法创建该用户的新任务。但是我在旧数据库上运行,如果end_date设置为null,很可能会有很多相同用途的记录,所以我不能在这里使用唯一的,每次插入之前我需要先检查
SELECT * FROM tasks WHERE end_date IS NOT null AND id_user = 2
如果没有记录,那么我可以为用户创建新任务。
将来很有可能在创建新任务之前添加更多条件以进行验证。
答案 0 :(得分:0)
了解InnoDB"交易"。了解SELECT ... FOR UPDATE
。
但是,对于这种情况,可以通过以下方式避免这两种情况:
UPDATE tasks SET active = 1 WHERE id_user = 2; -- not adequate
然后检查RowsAffected:0表示它没有激活。
使用修改,抓住我的UPDATE
;回到交易。在伪代码中:
BEGIN;
$active = SELECT active FROM tasks WHERE id_user = 2 FOR UPDATE;
if ($active) exit;
INSERT INTO tasks (id_user, active, task)
VALUES (2, 1, 'foo')
ON DUPLICATE KEY UPDATE active = 1 task = 'foo';
COMMIT;
这假设您有PRIMARY KEY(id_user)
。
答案 1 :(得分:0)
如果您的UNIQUE
索引可以防止重复,请执行以下操作:
INSERT IGNORE INTO tasks (id_user, active) VALUES (2,1)
这将忽略有关重复条目的警告。这具有仅添加一次记录的效果。