MySQL 在重复密钥更新时插入触发器之前 - 手册似乎有误?
MySQL before trigger for INSERT ON DUPLICATE KEY UPDATE - manual seems wrong?
我正在使用 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
更新插入按预期执行,但未重新生成 UUID。我用常量字符串试过了,得到了相同的结果。
现在,这正是我想要发生的事情;一个 BEFORE INSERT 无论采用哪个分支的 upsert 都会发生,这似乎毫无用处,或者至少这种行为似乎更有用。但这似乎与手册中所说的相反。有什么见解吗?
对重复项触发 BEFORE INSERT 触发器。您可以使用日志 table 对其进行测试。我已经在您的代码中添加了这样一个 table 并修改了触发器以填充 table:
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
table 有 4 行。最后一个包含 'fred'、'Alfred' 和一个新的 UUID。这意味着触发器已被触发。这也意味着已经生成了一个新的 UUID。但是那个 UUID 没有分配给 testtable.uuid
。您的代码中没有任何内容告诉您这样做。
如果你想在 ON DUPLICATE 部分分配新的 UUID(在触发器中生成),你可以使用 values(uuid)
:
访问它
insert into testtable (nickname, name) values ('fred', 'Alfred')
on duplicate key update
name='Alfred',
`uuid`=values(`uuid`);
我正在使用 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
更新插入按预期执行,但未重新生成 UUID。我用常量字符串试过了,得到了相同的结果。
现在,这正是我想要发生的事情;一个 BEFORE INSERT 无论采用哪个分支的 upsert 都会发生,这似乎毫无用处,或者至少这种行为似乎更有用。但这似乎与手册中所说的相反。有什么见解吗?
对重复项触发 BEFORE INSERT 触发器。您可以使用日志 table 对其进行测试。我已经在您的代码中添加了这样一个 table 并修改了触发器以填充 table:
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
table 有 4 行。最后一个包含 'fred'、'Alfred' 和一个新的 UUID。这意味着触发器已被触发。这也意味着已经生成了一个新的 UUID。但是那个 UUID 没有分配给 testtable.uuid
。您的代码中没有任何内容告诉您这样做。
如果你想在 ON DUPLICATE 部分分配新的 UUID(在触发器中生成),你可以使用 values(uuid)
:
insert into testtable (nickname, name) values ('fred', 'Alfred')
on duplicate key update
name='Alfred',
`uuid`=values(`uuid`);