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 尝试更新,看到 0 个受影响的行。
- 请求 2 次尝试更新,看到 0 个受影响的行。
- 请求 1 插入一条新记录。
- 请求 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
我需要更新数据库中的记录,但我不知道该记录是否已经存在。如果它存在,更新它,否则插入它。现在我想出了这个代码:
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 尝试更新,看到 0 个受影响的行。
- 请求 2 次尝试更新,看到 0 个受影响的行。
- 请求 1 插入一条新记录。
- 请求 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