PHP中mysql_影响_rows()的奇怪行为

PHP中mysql_影响_rows()的奇怪行为,php,mysql,Php,Mysql,我有一个名为user\u ips的表,用于跟踪用户,以防他们删除cookie或更改浏览器。总之,下面的代码很简单。它更新用户IP中与用户id和IP相同的条目。如果查询没有更新任何行,则表示该用户的IP不在表中,因此它会插入该行 $site->query('UPDATE `user_ips` SET `last_time` = UNIX_TIMESTAMP(), `user_agent` = \''.$this->user_agent.'\' WHERE `ip` = '.$this-

我有一个名为
user\u ips
的表,用于跟踪用户,以防他们删除cookie或更改浏览器。总之,下面的代码很简单。它更新用户IP中与用户id和IP相同的条目。如果查询没有更新任何行,则表示该用户的IP不在表中,因此它会插入该行

$site->query('UPDATE `user_ips` SET `last_time` = UNIX_TIMESTAMP(), `user_agent` = \''.$this->user_agent.'\' WHERE `ip` = '.$this->ip.' AND `userid` = '.$this->id);
if(mysql_affected_rows() == 0)
{
    $site->query('INSERT INTO `user_ips` SET `userid` = '.$this->id.', `ip` = '.$this->ip.', `first_time` = UNIX_TIMESTAMP(), `last_time` = UNIX_TIMESTAMP(), `user_agent` = \''.$this->user_agent.'\'');
}
问题是mysql\u impacted\u rows()有时返回0,即使存在具有用户当前ID和IP的行。因此,代码使用相同的IP向表中添加另一行


如果您想知道,$site是我为我的网站创建的mysql类,它执行的唯一查询是通过query()传递给它的查询,所以这个类没有问题。哦,IP存储为长IP,因此不需要在其周围加引号。

我在这里直接引用PHP文档:

使用UPDATE时,MySQL不会更新新值与旧值相同的列。这就产生了这样一种可能性,即mysql_impacted_rows()实际上可能并不等于匹配的行数,而只是实际受查询影响的行数


因此,在您的例子中,当UNIX_TIMESTAMP()返回相同的值时(例如,同一秒内来自同一客户机的两个请求),mysql_impacted_rows()将返回0

基于slipbull的答案,处理此问题的最简单方法可能是简单地执行SELECT查询,以评估是否需要插入。另一个解决方案是在用户创建时简单地插入一条记录,因为这将保证一条有效的记录。

您只需将主键设置为跨越userid和ip。这将确保您不会得到重复的条目,但如果您不打算添加select以检查记录是否存在,则必须抑制insert查询中的错误。

另一个选项可能是使用MySQL REPLACE命令。这将删除该行(如果该行已存在),然后插入该行


虽然这可能不适合您的精确需求。

我之前正在执行另一个SELECT COUNT(*)查询以进行检查,但我将其更改为此“保存一个查询”。但我想我得回去了。我不认为这在MySQL中是可能的。一个用户可以有多个IP,一个IP可能属于多个用户。因此,用户ID和IP的组合必须是唯一的。这就是跨越两列的主键的作用。强制两者都是唯一的,而不是单独的。