PHP中mysql_affected_rows()的奇怪行为

时间:2009-07-27 13:45:48

标签: php mysql

我有一个名为user_ips的表来跟踪用户,以防他们删除Cookie或更改浏览器。所以无论如何,以下代码很简单。它更新user_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_affected_rows()有时会返回0,即使存在具有用户当前ID和IP的行也是如此。那么代码就会在表中添加另一行,并使用相同的IP。

如果您想知道,$ site是我为我的网站制作的mysql类,它执行的唯一查询是query()传递给它的那个,仅此而已,所以这不是类的问题。哦,IP存储为长IP,因此它不需要引号。

4 个答案:

答案 0 :(得分:7)

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

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

因此,在您的情况下,当UNIX_TIMESTAMP()返回相同的值时,mysql_affected_rows()将返回0(例如,来自同一客户端的两个请求在同一秒内)。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

另一种选择可能是使用MySQL REPLACE命令。 http://dev.mysql.com/doc/refman/5.0/en/replace.html。如果该行已存在,将删除该行,然后插入该行。

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