MySQL INSERT .... ON DUPLICATE UPDATE - 在自动增量中添加一个

时间:2011-08-17 04:15:37

标签: php mysql innodb

我通过简单的点击计数器跟踪访问我的所有http_user_agents。 下面在数据库中插入http_user_agent,此字段为Case Insensitive且为Unique。因此,当我们尝试插入它并找到一个DUPLICATE KEY时,它会向hits字段添加1。

问题是我的自动增量字段仍然增加,即使我们没有插入字段。我怎么能阻止这个?

$sql = "INSERT INTO `db_agency_cloud`.`tblRefHttpUsersAgent` SET `http_users_agent` = :UsersAgent, `created_ts` = NOW() ON DUPLICATE KEY UPDATE `hits` = `hits` + 1";

这是表结构:

CREATE TABLE `tblRefHttpUsersAgent`
(
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`http_users_agent` varchar(255) NOT NULL,
`hits` int(20) unsigned NOT NULL DEFAULT '1',
`created_ts` datetime NOT NULL,
`activity_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `http_users_agent` (`http_users_agent`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

4 个答案:

答案 0 :(得分:18)

为了InnoDB的INSERT ... ON DUPLICATE KEY UPDATE处理,

AUTO_INCREMENT被描述为“混合模式插入”。混合模式插入基本上是已知最大所需AUTO_INCREMENT值的数量,但实际需要的数量不是。

默认情况下会专门处理混合模式插入,如MySQL docs

中所述
  

...用于“混合模式插入”...... InnoDB会   分配比行数更多的自动增量值   插入。但是,所有自动分配的值都是连续的   生成(并因此高于)生成的自动增量值   最近执行的先前声明。 “过剩”的数字是   丢失。

如果你正在使用InnoDB,那么你的选择是:

  1. 避免使用INSERT ... ON DUPLICATE KEY UPDATE
  2. innodb_autoinc_lock_mode参数设置为0,用于“传统”自动增量锁定模式,这样可以保证所有INSERT语句都为AUTO_INCREMENT列分配连续值。但是,这是通过在语句期间锁定来实现的,因此与此设置相关的性能损失。
  3. (推荐)忽略AUTO_INCREMENT列中的间隙。
  4. 注意:AUTO_INCREMENT处理在MyISAM下完全不同,MyISAM没有表现出这种行为。

答案 1 :(得分:5)

存储引擎必须在插入行之前递增AUTO_INCREMENT值。它不知道插入是否会在那时失败。它不能简单地回滚增量,因为可能同时在其他连接上发生其他插入。这是正常行为,而不是您应该(或可以)改变的行为。 AUTO_INCREMENT的目的是提供唯一标识符,而不是不间断的数字序列。

答案 2 :(得分:1)

不幸的是,如果您不想影响自动增量ID,则解决方案处于应用程序级别。首先执行SELECT并计算结果行。如果为0,则INSERT数据。如果大于0,则UPDATE表示行。

答案 3 :(得分:0)

您可以首先计算插入的最大行数,然后将其加1,

git checkout $(git describe --tags)

然后使用一些变量(SELECT MAX(`id`)+1 FROM `tblRefHttpUsersAgent`) AUTO_INCREMENT / SET @NEW_ID语句更改表PREPARE

here是针对同一问题的简单解决方案,如果您喜欢自己的特定问题的解决方案,则以下为最终版本:

EXECUTE