要回答您最初的问题,检查是否存在重复的最简单方法是针对您要添加的内容运行 SQL 查询!
例如,如果您想在表 links 中检查 url http://www.example.com/,那么您的查询将类似于
SELECT * FROM links WHERE url = 'http://www.example.com/';
你的 PHP 代码看起来像
$conn = mysql_connect('localhost', 'username', 'password');
if (!$conn)
{
die('Could not connect to database');
}
if(!mysql_select_db('mydb', $conn))
{
die('Could not select database mydb');
}
$result = mysql_query("SELECT * FROM links WHERE url = 'http://www.example.com/'", $conn);
if (!$result)
{
die('There was a problem executing the query');
}
$number_of_rows = mysql_num_rows($result);
if ($number_of_rows > 0)
{
die('This URL already exists in the database');
}
我已经在这里写了这个,所有连接到数据库等等。很可能你已经有一个到数据库的连接,所以你应该使用它而不是开始一个新的连接(替换@ mysql_query 命令中的 987654325@ 并删除与 mysql_connect 和 mysql_select_db 相关的内容)
当然,还有其他方法可以连接到数据库,例如 PDO,或使用 ORM 或类似方法,所以如果您已经在使用这些方法,那么这个答案可能不相关(而且可能有点超出范围在这里给出与此相关的答案!)
然而,MySQL 提供了许多方法来防止这种情况发生。
首先,您可以将字段标记为“唯一”。
假设我有一个表,我想在其中存储从我的网站链接到的所有 URL,以及上次访问它们的时间。
我的定义可能是这样的:-
CREATE TABLE links
(
url VARCHAR(255) NOT NULL,
last_visited TIMESTAMP
)
这将允许我一遍又一遍地添加相同的 URL,除非我编写了一些类似于上面的 PHP 代码来阻止这种情况发生。
但是,我的定义是否要更改为
CREATE TABLE links
(
url VARCHAR(255) NOT NULL,
last_visited TIMESTAMP,
PRIMARY KEY (url)
)
那么当我尝试两次插入相同的值时,这会使mysql抛出错误。
PHP 中的一个例子是
$result = mysql_query("INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()", $conn);
if (!$result)
{
die('Could not Insert Row 1');
}
$result2 = mysql_query("INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()", $conn);
if (!$result2)
{
die('Could not Insert Row 2');
}
如果你运行它,你会发现在第一次尝试时,脚本会因为注释Could not Insert Row 2 而死掉。但是,在随后的运行中,它会以 Could not Insert Row 1 消失。
这是因为 MySQL 知道 url 是表的 Primary Key。主键是该行的唯一标识符。大多数情况下,将行的唯一标识符设置为数字很有用。这是因为 MySQL 查找数字比查找文本更快。在 MySQL 中,键(尤其是主键)用于定义两个表之间的关系。例如,如果我们有一个用户表,我们可以将其定义为
CREATE TABLE users (
username VARCHAR(255) NOT NULL,
password VARCHAR(40) NOT NULL,
PRIMARY KEY (username)
)
但是,当我们想要存储有关用户发布的帖子的信息时,我们必须将用户名与该帖子一起存储,以识别该帖子属于该用户。
我已经提到 MySQL 在查找数字方面比字符串更快,所以这意味着我们会花时间在不必要的时候查找字符串。
为了解决这个问题,我们可以添加一个额外的列 user_id,并将其作为主键(这样在根据帖子查找用户记录时,我们可以更快地找到它)
CREATE TABLE users (
user_id INT(10) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL,
password VARCHAR(40) NOT NULL,
PRIMARY KEY (`user_id`)
)
您会注意到我在这里还添加了一些新内容 - AUTO_INCREMENT。这基本上允许我们让该领域自己照顾自己。每次插入新行时,它会将前一个数字加 1,并将其存储起来,因此我们不必担心编号,只需让它自己完成即可。
所以,有了上面的表格,我们可以做类似的事情
INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671');
然后
INSERT INTO users (username, password) VALUES('User', '988881adc9fc3655077dc2d4d757d480b5ea0e11');
当我们从数据库中选择记录时,我们得到以下信息:-
mysql> SELECT * FROM users;
+---------+----------+------------------------------------------+
| user_id | username | password |
+---------+----------+------------------------------------------+
| 1 | Mez | d3571ce95af4dc281f142add33384abc5e574671 |
| 2 | User | 988881adc9fc3655077dc2d4d757d480b5ea0e11 |
+---------+----------+------------------------------------------+
2 rows in set (0.00 sec)
但是,在这里 - 我们有一个问题 - 我们仍然可以添加另一个具有相同用户名的用户!显然,这是我们不想做的事情!
mysql> SELECT * FROM users;
+---------+----------+------------------------------------------+
| user_id | username | password |
+---------+----------+------------------------------------------+
| 1 | Mez | d3571ce95af4dc281f142add33384abc5e574671 |
| 2 | User | 988881adc9fc3655077dc2d4d757d480b5ea0e11 |
| 3 | Mez | d3571ce95af4dc281f142add33384abc5e574671 |
+---------+----------+------------------------------------------+
3 rows in set (0.00 sec)
让我们改变我们的表定义!
CREATE TABLE users (
user_id INT(10) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL,
password VARCHAR(40) NOT NULL,
PRIMARY KEY (user_id),
UNIQUE KEY (username)
)
让我们看看当我们现在尝试插入同一个用户两次时会发生什么。
mysql> INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671');
ERROR 1062 (23000): Duplicate entry 'Mez' for key 'username'
嘘!!当我们第二次尝试插入用户名时,我们现在得到一个错误。使用类似上面的方法,我们可以在 PHP 中检测到这一点。
现在,让我们回到我们的链接表,但有一个新的定义。
CREATE TABLE links
(
link_id INT(10) NOT NULL AUTO_INCREMENT,
url VARCHAR(255) NOT NULL,
last_visited TIMESTAMP,
PRIMARY KEY (link_id),
UNIQUE KEY (url)
)
让我们将“http://www.example.com”插入数据库。
INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW());
如果我们再次尝试插入它......
ERROR 1062 (23000): Duplicate entry 'http://www.example.com/' for key 'url'
但是如果我们想更新上次访问的时间会发生什么?
好吧,我们可以用 PHP 做一些复杂的事情,像这样:-
$result = mysql_query("SELECT * FROM links WHERE url = 'http://www.example.com/'", $conn);
if (!$result)
{
die('There was a problem executing the query');
}
$number_of_rows = mysql_num_rows($result);
if ($number_of_rows > 0)
{
$result = mysql_query("UPDATE links SET last_visited = NOW() WHERE url = 'http://www.example.com/'", $conn);
if (!$result)
{
die('There was a problem updating the links table');
}
}
或者,甚至获取数据库中行的 id 并使用它来更新它。
$result = mysql_query("SELECT * FROM links WHERE url = 'http://www.example.com/'", $conn);
if (!$result)
{
die('There was a problem executing the query');
}
$number_of_rows = mysql_num_rows($result);
if ($number_of_rows > 0)
{
$row = mysql_fetch_assoc($result);
$result = mysql_query('UPDATE links SET last_visited = NOW() WHERE link_id = ' . intval($row['link_id'], $conn);
if (!$result)
{
die('There was a problem updating the links table');
}
}
但是,MySQL 有一个很好的内置功能,称为 REPLACE INTO
让我们看看它是如何工作的。
mysql> SELECT * FROM links;
+---------+-------------------------+---------------------+
| link_id | url | last_visited |
+---------+-------------------------+---------------------+
| 1 | http://www.example.com/ | 2011-08-19 23:48:03 |
+---------+-------------------------+---------------------+
1 row in set (0.00 sec)
mysql> INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW());
ERROR 1062 (23000): Duplicate entry 'http://www.example.com/' for key 'url'
mysql> REPLACE INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW());
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT * FROM links;
+---------+-------------------------+---------------------+
| link_id | url | last_visited |
+---------+-------------------------+---------------------+
| 2 | http://www.example.com/ | 2011-08-19 23:55:55 |
+---------+-------------------------+---------------------+
1 row in set (0.00 sec)
注意,使用REPLACE INTO时,更新了last_visited时间,并没有抛出错误!
这是因为 MySQL 检测到您正在尝试替换行。它知道您想要的行,因为您已将 url 设置为唯一。 MySQL 通过使用您传入的应该是唯一的位(在本例中为 url)并为该行更新其他值来计算要替换的行。它还更新了 link_id - 这有点出乎意料! (事实上,直到我看到它发生时,我才意识到会发生这种情况!)
但是如果你想添加一个新的 URL 怎么办?好吧,REPLACE INTO 如果找不到匹配的唯一行,它会很高兴地插入一个新行!
mysql> REPLACE INTO links (url, last_visited) VALUES ('http://www.stackoverflow.com/', NOW());
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM links;
+---------+-------------------------------+---------------------+
| link_id | url | last_visited |
+---------+-------------------------------+---------------------+
| 2 | http://www.example.com/ | 2011-08-20 00:00:07 |
| 3 | http://www.stackoverflow.com/ | 2011-08-20 00:01:22 |
+---------+-------------------------------+---------------------+
2 rows in set (0.00 sec)
我希望这能回答您的问题,并为您提供有关 MySQL 工作原理的更多信息!