我最近从单个 MySQL 安装切换到 MySQL Galera,它在通过 HAProxy 寻址的 3 个节点上运行。自从切换以来,我确实随机报告了“重复密钥”错误,这在理论上应该是不可能的,因为我会检查数据集是否已经可用。
例如:
MySQL Error executing stmt:
INSERT INTO user_ips
(user_id,ip)
VALUES
('444079','41.205.7.198, 176.9.19.101')
Error No: 1062
Error: Duplicate entry '444079-41.205.7.198, 1' for key 'user_id'
我的代码如下所示:
function save_user_ip($user_id){
global $T62, $link;
$ip = $_SERVER['REMOTE_ADDR'];
// do we already know that user by this ip?
$stmt="
SELECT ID AS ip_id
FROM $T62
WHERE user_id = '$user_id' AND ip = '$ip'
";
$row = db_get_row2($stmt);
$ip_id = isset($row->ip_id) ? $row->ip_id : "";
if (!$ip_id){ // ip unknown for that user, save it
$stmt="
INSERT INTO $T62
(user_id,ip)
VALUES
('$user_id','$ip')
";
db_query($stmt);
$ip_id = db_insertid($link);
}
return $ip_id;
}
在测试页上运行它按预期工作。然而,在负载下的生产服务器上,它并不总是有效。我考虑过 INSERT IGNORE 但不想在所有操作上运行插入,因为写入速度较慢并且还会触发警告。
运行SHOW CREATE TABLE tablename
会创建以下输出:1146 - 表“tablename”不存在
一种似乎至少适用于开发集群的可能解决方案:
// save ip. Will ignore if already known ip
$stmt="
INSERT IGNORE INTO $T62
(user_id,ip)
VALUES
('$user_id','$ip')
";
#echo $stmt; exit;
db_query($stmt);
$ip_id = db_insertid($link);
// if ip already known, retrieve it
if (!$ip_id){
$stmt="
SELECT ID AS ip_id
FROM $T62
WHERE user_id = '$user_id' AND ip = '$ip'
";
$row = db_get_row2($stmt);
$ip_id = $row->ip_id;
}
return $ip_id;
不确定这会如何改善产品的情况,或者是否会让事情变得更糟。可能有更优雅的解决方案。
在此先感谢您提供的任何帮助。
用户错误。
从什么时候开始
ip
看起来像41.205.7.198, 176.9.19.101
?444079-41.205.7.198, 1
暗示那41.205.7.198, 1
是用作ip
. 那是前 15 个字符,所以我猜你有VARCHAR(15)
. (注意:这就是为什么第一条评论要求SHOW CREATE TABLE
.)因此,您的有趣 IP 被截断,导致用户导致 DUP KEY。