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 结构中,您在 user
和 post
上根本没有索引,并且在您的应用程序中,您执行 select 并查找两个列,这将导致完整的 table 扫描。
使用唯一索引 (user,post)
你可以跳过 select 因为当违反唯一约束时你会得到一个 SQL 错误。
另外 user
和 post
是外键,因此无论如何都应该对其进行索引。
唯一索引 (user,post)
涵盖 user
FK,因此您还需要单独索引 post
我有一个 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 结构中,您在 user
和 post
上根本没有索引,并且在您的应用程序中,您执行 select 并查找两个列,这将导致完整的 table 扫描。
使用唯一索引 (user,post)
你可以跳过 select 因为当违反唯一约束时你会得到一个 SQL 错误。
另外 user
和 post
是外键,因此无论如何都应该对其进行索引。
唯一索引 (user,post)
涵盖 user
FK,因此您还需要单独索引 post