重复KEY上的PHP + MYSQL仍会增加INDEX KEY

时间:2015-08-14 19:56:23

标签: php mysql

我的桌子有这种风格:

ID - EMAIL - VERSION - LASTUPDATE

其中id =是自动增量,主要是:

和电子邮件是UNIQUE

因此,每当有人使用我的应用程序时,它会获取用户电子邮件并尝试插入,如果电子邮件已经存在,则将行更新为$ version和$ lastupdate的新值

它几乎100%工作,它已经完全更新了行,问题是当它执行UPDATE时,仍然会增加自动增量id,所以下一个INSERT将不是lastID加一个,而将是另一个数字例如:

ID - EMAIL - VERSION - LASTUPDATE
-----------------------------------
1 - test1@... - 1.0 - currentTime();

如果test2加载我的应用程序,它将添加,数据库将是:

ID - EMAIL - VERSION - LASTUPDATE
-----------------------------------
1 - test1@.. - 1.0 - currentTime();
2 - test2@.. - 1.0 - currentTime();

所以现在想象一下test2有新版本并且更新为:

ID - EMAIL - VERSION - LASTUPDATE
-----------------------------------
1 - test1@.. - 1.1 - currentTime();
2 - test2@.. - 1.0 - currentTime();

完全不是吗?所以问题开始时test3打开我的应用程序,id不会是3,它将是4因为更新增加了1个id(我不知道为什么)

ID - EMAIL - VERSION - LASTUPDATE
-----------------------------------
1 - test1@.. - 1.1 - currentTime();
2 - test2@.. - 1.0 - currentTime();
4 - test3@.. - 1.1 - currentTime();

为什么在更新时它会增加ID的加号?我不想要它=(

我的sql语法:

$sql = "INSERT INTO `backups`.`regs` (`email`, `version`, `lastupdate`) VALUES ('$email', '$version', '$lastupdate')  ON DUPLICATE KEY UPDATE version='$version', lastupdate='$lastupdate'";

3 个答案:

答案 0 :(得分:3)

好吧,是的,现在我记得这个问题。曾经有一个人想要插入,但如果可以想象,每个插入必须以100为增量,从@ 1000开始。而且我们必须将整个事件包装在存储过程中,以便有一个漏洞。你的问题浮出水面,它将他的编号抛弃了1个左右。

通过包装它,我们可以理所当然地做一个点,使用锁定,并使用ALTER TABLE

维护auto_inc值

我告诉他的另一种方法是有一个增量表,锁定1行,获取该行中的值,使用它,将incTable更新为100.解锁。

我们一直在笑着强迫症问题。我认为他只喜欢10的倍数,idk

编辑:

架构:

-- drop table ocd_nextnums;
create table ocd_nextnums
(   -- id table for nextnum, for the OCD impaired
    tableName varchar(100) not null,
    nextnum int not null
    -- won't bother with indexes, go for it if you want
)engine=INNODB; -- note engine type

insert ocd_nextnums(tableName,nextnum) values('thing',1);
insert ocd_nextnums(tableName,nextnum) values('some_other_table',1);

-- drop table thing;
create table thing
(   id int primary key, -- NOT an auto_increment, but is a PK
    email varchar(100) not null,
    version varchar(20) not null,
    lastupdate datetime not null,
    UNIQUE KEY (email)
)engine=MyIsam;

存储过程:

-- drop procedure putInThing;
delimiter $$
create procedure putInThing
(
    email_In varchar(100), version_In varchar(20)
)
BEGIN
    declare toUse int;
    declare theCount int;

    select count(*) into theCount from thing where email=email_In;
    select id into toUse from thing where email=email_In;   -- useful for result set @end
    IF theCount=1 THEN
        -- was there, do UPDATE
        update thing set version=version_In,lastupdate=now() where email=email_In;
    ELSE
        -- new row, do INSERT (please note the FOR UPDATE clause)
        select nextnum into toUse from ocd_nextnums where tableName='thing' FOR UPDATE;
        update ocd_nextnums set nextnum=nextnum+1 where tableName='thing';

        insert thing(id,email,version,lastupdate) values (toUse,email_In,version_In,now());
    end if;
    select toUse;   -- <------- that was your id
END
$$

测试:

call putInThing('t1@t.com','111');
call putInThing('t2@t.com','121');
call putInThing('t3@t.com','107');
select * from thing;
+----+----------+---------+---------------------+
| id | email    | version | lastupdate          |
+----+----------+---------+---------------------+
|  1 | t1@t.com | 111     | 2015-08-14 17:08:10 |
|  2 | t2@t.com | 121     | 2015-08-14 17:08:54 |
|  3 | t3@t.com | 107     | 2015-08-14 17:08:56 |
+----+----------+---------+---------------------+

call putInThing('t3@t.com','101111007'); -- is an update
call putInThing('t3@t.com','42'); -- is an update
call putInThing('t3@t.com','10007'); -- is an update
call putInThing('h@hillaryclinton.com','1'); -- is an insert

select * from thing;
+----+----------------------+---------+---------------------+
| id | email                | version | lastupdate          |
+----+----------------------+---------+---------------------+
|  1 | t1@t.com             | 111     | 2015-08-14 17:08:10 |
|  2 | t2@t.com             | 121     | 2015-08-14 17:08:54 |
|  3 | t3@t.com             | 10007   | 2015-08-14 17:22:09 |
|  4 | h@hillaryclinton.com | 1       | 2015-08-14 17:22:47 |
+----+----------------------+---------+---------------------+

来自Manual的Mysql INNODB部分:

  

要实现读取和递增计数器,首先执行a   使用FOR UPDATE锁定计数器的读取,然后递增   计数器.....

你会看到我使用它,可能不是。只是展示它。我很好,有间隙,晚上睡觉。这就是我为第一张桌子命名的原因:&gt;

答案 1 :(得分:2)

在你执行插入之前,你所描述的你在$ version中有错误的值。这是填写在你没有向我们展示过的代码中的。

您应该使用数据库中已保存的版本号:

INSERT INTO `backups`.`regs` 
(`email`, `version`, `lastupdate`) 
VALUES ('$email', 1, '$lastupdate')  
ON DUPLICATE KEY 
UPDATE version=version+1, lastupdate='$lastupdate'"

答案 2 :(得分:1)

因为您已经传递了这些值,所以您应该version = VALUES(version), lastupdate = VALUES(lastupdate)使用ON DUPLICATE,试试这个:

$sql = "INSERT INTO `backups`.`regs` (`email`, `version`, `lastupdate`) VALUES ('$email', '$version', '$lastupdate')  ON DUPLICATE KEY UPDATE version = VALUES(version), lastupdate = VALUES(lastupdate)";