MYSQL 使用 PHP 更新或插入

MYSQL update or insert with PHP

我需要更新数据库中的记录,但我不知道该记录是否已经存在。如果它存在,更新它,否则插入它。现在我想出了这个代码:

1: <?php
2: $query = "UPDATE user_meta SET active = '0' WHERE user_id = '125'";
3: $mysqli->query($query);
4: 
5: if($mysqli->affected_rows == 0){
6:     $query = "INSERT INTO user_meta (user_id, active) VALUES ('125', 0)";
7:     $mysqli->query($query);
8: }

table:

CREATE TABLE `user_meta` (
  `user_id` int(11) DEFAULT NULL,
  `active` tinyint(4) DEFAULT NULL,
  UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这段代码对我来说工作正常,但它实际上产生了一个我忽略的错误。

问题出在这一行5。如果没有任何更改,即使记录已经存在,affected_rows 也是 0。但这会触发 INSERT 语句。这个失败是因为 user_id 字段是唯一的,现在我忽略了这一点,所以我的代码工作正常。

但这是要走的路吗? 或者我应该先做一个 select 然后更新或插入?

您可以使用 INSERT ... ON DUPLICATE KEY

解决此问题

使用此方法在事务上是安全的,因为 MySQL 在一个隐式事务中处理它。您当前的方法允许两个并发请求相互干扰的分裂时刻。

假设您使用的是 MySQL 5.7:https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html

您的查询将如下所示:

INSERT INTO user_meta SET user_id = 125, active = 0
  ON DUPLICATE KEY UPDATE active = 0

更新: 只是为了详细说明为什么您当前的方法在事务上 不安全 ,想象一下两个并行执行的并发请求。

  1. 请求 1 尝试更新,看到 0 个受影响的行。
  2. 请求 2 次尝试更新,看到 0 个受影响的行。
  3. 请求 1 插入一条新记录。
  4. 请求 2 插入一条新记录。

您是明确地开始并完成交易,还是隐含地进行交易(例如通过INSERT ... ON DUPLICATE KEY)MySQL 将负责确保不会发生上述错误情况,方法是在第一个请求完成之前阻止第二个请求。

MySQL 有一个内置的解决方案 - on duplicate key update 子句:

INSERT INTO user_meta (user_id, active) 
VALUES (125, 0)
ON DUPLICATE KEY UPDATE active = 0

使用mysql ON DUPLICATE KEY UPDATE检查记录是否已经存在于数据库中。您的 table 必须有一个具有 unique 类型的列。这里您的 user_id 列是唯一类型。检查文档 here

INSERT INTO user_meta (user_id, active) 
VALUES (125, 0)
ON DUPLICATE KEY UPDATE active = 0