数据库
首页 > 数据库> > MySQL在触发INSERT ON DUPLICATE KEY UPDATE之前 – 手动似乎错了?

MySQL在触发INSERT ON DUPLICATE KEY UPDATE之前 – 手动似乎错了?

作者:互联网

我正在使用MySQL 5.7:

D:\>mysql --version
mysql  Ver 14.14 Distrib 5.7.17, for Win64 (x86_64)

根据manual,BEFORE INSERT触发器的行为应该是:

a BEFORE INSERT trigger activates for every row, followed by either an
AFTER INSERT trigger or both the BEFORE UPDATE and AFTER UPDATE
triggers, depending on whether there was a duplicate key for the row.

我认为这意味着无论是否存在重复的密钥匹配都会执行BEFORE INSERT,而AFTER INSERT和UPDATE触发器取决于是否存在密钥冲突. This SO重复相同.但是,我没有看到这种行为.这是我做的:

create table testtable (
  id integer primary key auto_increment,
  nickname varchar(40),    -- this is the natural key to be unique indexed
  name varchar(40),
  uuid varchar(36));       -- this is what I want to assign in the trigger

alter table testtable add unique index testtable_ux (nickname);
create trigger testtable_uid before insert on testtable for each row set
  new.uuid=uuid();

-- get some data
insert into testtable (nickname, name) values ('bob', 'Robert'), 
  ('fred', 'Frederick'), ('cha', 'Chauncey');
select * from testtable;

1   bob   Robert      06fb18be-f87e-11e6-8e6f-0060737a7c01
2   fred  Frederick   06fb1a5d-f87e-11e6-8e6f-0060737a7c01
3   cha   Chauncey    06fb1aec-f87e-11e6-8e6f-0060737a7c01

很好 – 每个人都有一个独特的UUID.现在好了,根据手册,这个BEFORE INSERT触发器应该被执行,无论是否有重复的密钥,所以即使我得到重复的密钥更新,UUID也应该更新 – 对吗?让我们来看看:

insert into testtable (nickname, name) values ('fred', 'Alfred') 
  on duplicate key update name='Alfred';
3   88  16:39:32 ... 2 row(s) affected  0.032 sec

select * from testtable;
1   bob   Robert      06fb18be-f87e-11e6-8e6f-0060737a7c01
2   fred  Alfred      06fb1a5d-f87e-11e6-8e6f-0060737a7c01
3   cha   Chauncey    06fb1aec-f87e-11e6-8e6f-0060737a7c01

嗯,名字已更新.让我们比较一下UUID:

2   fred  Frederick   06fb1a5d-f87e-11e6-8e6f-0060737a7c01
2   fred  Alfred      06fb1a5d-f87e-11e6-8e6f-0060737a7c01

upsert按预期执行,但UUID未重新生成.我用常量字符串尝试了这个并得到了相同的结果.

现在,这正是我想要发生的事情; BEFORE INSERT无论upsert的哪个分支被发生都会发生似乎没用,或者至少这种行为似乎更有用.但这似乎与手册所说的相反.任何见解?

解决方法:

BEFORE INSERT触发器在重复项上触发.您可以使用日志表进行测试.我已经在代码中添加了这样一个表,并修改了触发器来填充该表:

drop table if exists testtable;
create table testtable (
  id integer primary key auto_increment,
  nickname varchar(40),    -- this is the natural key to be unique indexed
  name varchar(40),
  uuid varchar(36));       -- this is what I want to assign in the trigger

alter table testtable add unique index testtable_ux (nickname);

drop table if exists testlog;
create table testlog (
  log_id int primary key auto_increment,
  nickname varchar(40),
  name varchar(40),
  uuid varchar(36)
);

drop trigger if exists testtable_uid;
delimiter //
create trigger testtable_uid before insert on testtable for each row
begin
  set new.uuid=uuid();
  insert into testlog (nickname, name, uuid) values (new.nickname, new.name, new.uuid);
end //
delimiter ;

insert into testtable (nickname, name) values ('bob', 'Robert'), 
  ('fred', 'Frederick'), ('cha', 'Chauncey');
select * from testtable;

insert into testtable (nickname, name) values ('fred', 'Alfred') 
  on duplicate key update name='Alfred';

select * from testtable;
select * from testlog;

您将看到testlog表有4行.最后一个包含’fred’,’Alfred’和一个新的UUID.这意味着触发器已被触发.这也意味着已经生成了一个新的UUID.但是UUID没有分配给testtable.uuid.您的代码中没有任何内容可以告诉您这样做.

如果希望在ON DUPLICATE部分中分配新的UUID(在触发器中生成),则可以使用值(uuid)访问它:

insert into testtable (nickname, name) values ('fred', 'Alfred') 
  on duplicate key update 
    name='Alfred',
    `uuid`=values(`uuid`);

标签:mysql,upsert
来源: https://codeday.me/bug/20190627/1308189.html