MyISAM 的意外双插入

Unexpected double inserts with MyISAM

我有一个 like table 供客户喜欢我网站上的产品。

问题是,我用这个 table:

CREATE TABLE IF NOT EXISTS `likes` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user` varchar(40) NOT NULL,
  `post` int(11) UNSIGNED NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;

喜欢的用户,post是商品id

点赞按钮向此 php:

发送 ajax 请求
session_start();
$user = $_SESSION["user"];
$pinsid=$_POST['id'];

$stmt = $mysqli_link->prepare("SELECT * FROM likes WHERE post=? AND user=?");
$stmt->bind_param('is', $pinsid, $user);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
$chknum = $result->num_rows;

if($chknum==0){
    $stmt = $mysqli_link->prepare("INSERT INTO likes (user, post) VALUES (?,?)");
    $stmt->bind_param('si', $user, $pinsid);
    $stmt->execute();
    $stmt->close();
    $response = 'success';
 }

echo json_encode($response);

我的问题是,我有来自同一个人的双重插入。例如:

1 josh 5
2 josh 5

但只有 MySQL 引擎设置为 InnoDB 时才会发生,如果我将其更改为 MyISAM,我只有 1 个插入。

这是怎么回事?我应该怎么做才能让它正常工作?

这样做的一种方法是为用户和post设置一个唯一的密钥table(参见https://dev.mysql.com/doc/refman/5.0/en/constraint-primary-key.html)。

如果这样,数据库将确保没有重复的用户和 post。但是,对于已经在 table 中的数据,如果已经有重复项

,则可能会出现问题

but it only happens if MySQL engine is set as InnoDB, if I change it to MyISAM I have only 1 insert. What is happening? What should I do to make it work properly?

MyISAM 引擎使用 table 级锁定,这意味着如果一个操作正在 table 上执行,所有其他操作将等待执行直到该操作完成。

InnoDb 是事务性的并使用行级锁定,因为您没有使用事务,所以没有任何东西被锁定。

如评论和答案中所述,最简单的解决方案是在用户和 post 上创建唯一约束,在这种情况下,您可以将两者用作主键,因为自动递增列没有附加值.

创建唯一约束:

ALTER TABLE likes ADD UNIQUE KEY uk_user_post (user,post);

关于你的问题:

but it can slow down my inserts?

如果我们只谈论 table 处的插入操作,是的,它确实变慢了,因为每个索引都必须在插入、更新或删除操作后重建。它减慢多少取决于索引的大小和 table.

中的行数

然而,在您当前的 table 结构中,您在 userpost 上根本没有索引,并且在您的应用程序中,您执行 select 并查找两个列,这将导致完整的 table 扫描。

使用唯一索引 (user,post) 你可以跳过 select 因为当违反唯一约束时你会得到一个 SQL 错误。

另外 userpost 是外键,因此无论如何都应该对其进行索引。

唯一索引 (user,post) 涵盖 user FK,因此您还需要单独索引 post