有些情况下,我们需要更新数据表中一条记录的状态,然后再取出来,但是这时候,如果在更新之前没有主键来确认记录的唯一性,就没有办法了知道哪条记录已更新。
例如:
有一个发行新手卡的程序。 设计数据库时有两种常见的解决方案:
方案一:使用一张表,新手卡和采集记录放在一起,所以主要字段有新手卡(主键)、用户ID(唯一)、采集状态(非必须)等。
这样的话数据库操作就简单了,就一条sql,更新用户id到这张表,然后根据用户id就出来了。 不过这种方式记录较多时的效率问题暂时不讨论。
方案二:使用两张表,一张存放新手卡,一张存放收藏记录。 新手卡表包含新手卡(主键)、新手卡状态等字段。
操作方式也有两种:
一种是先从新手卡表中取出一条记录,然后更新其状态,然后插入到收藏记录表中。
但这种方法最大的问题是,在高并发的情况下,多个用户会生成同一条记录,所以只有一个人能够成功,其他人都会失败。
第二种是从新手卡中更新一条记录,然后取出这条记录插入到集合记录表中。 因为是第一个,所以非常适合高并发的情况。
但现在遇到了上面提到的问题:如何获取刚刚更新的记录的ID?
下面的代码是上面找到的答案,借用一下:
SET @update_id := 0;
UPDATE some_table SET row = 'value', id = (SELECT @update_id := id)
WHERE some_other_row = 'blah' LIMIT 1;
SELECT @update_id;
大致思路是先声明一个用户变量@,然后再更新数据中的一个字段,即将当前主键值更新为当前主键值(实际上并没有更新)。 更新主键字段不是目的,而是更新当前的主键值赋值给@,也就是这句话:(@:=id)。 (个人理解,水平有限可能有所不同)
另外,如果更新多条记录,还可以使用下面的方法
SET @uids := null;
UPDATE footable
SET foo = 'bar'
WHERE fooid > 5
AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;
注意:以上方法不适用于带有 GROUP BY 或 ORDER BY 的子句,否则结果可能与预期不同。
参考官方手册的说明