【发布时间】:2011-03-18 13:23:33
【问题描述】:
假设我要在 MySQL/InnoDB 中模拟自动增量
条件
- 使用 MySQL/InnoDB
- ID字段没有唯一索引,也不是PK
是否可以仅使用程序逻辑进行模拟,而无需表级锁定。 谢谢。
【问题讨论】:
假设我要在 MySQL/InnoDB 中模拟自动增量
条件
是否可以仅使用程序逻辑进行模拟,而无需表级锁定。 谢谢。
【问题讨论】:
创建另一个表,其中包含存储下一个 id 值的单行和单列。然后在原始表上创建一个插入触发器,该触发器增加第二个表中的值,获取它,并将其用于第一个表上的 ID 列。您需要小心选择和更新的方式,以确保它们是原子的。
本质上,您是在 MySQL 中模拟 Oracle sequence。但是,它会导致序列表中的单行锁定,因此可能不适合您正在执行的操作。
预计到达时间:
另一个类似但性能可能更好的选项是创建第二个“序列”表,该表只有一个自动增量 PK 列,没有其他数据。让您的插入触发器在该表中插入一行,并使用从那里生成的 ID 填充原始表中的 ID。然后让触发器或另一个进程定期从序列表中删除所有行以清理它。
【讨论】:
CREATE TABLE sequence (id INTEGER); -- possibbly add a name;
INSERT INTO sequence VALUES (1); -- starting value
SET AUTOCOMMIT=0;
START TRANSACTION;
UPDATE sequence SET id = LAST_INSERT_ID(id+1);
INSERT INTO actualtable (non_autoincrementing_key) VALUES (LAST_INSERT_ID());
COMMIT;
SELECT LAST_INSERT_ID(); 甚至是一个会话安全值,用于检查您获得的 ID。确保您的表支持事务,或者序列中的漏洞没有问题。
【讨论】:
sequence table需要有id作为自增PK
【讨论】:
使用序列表和触发器 - 类似这样:
drop table if exists users_seq;
create table users_seq
(
next_seq_id int unsigned not null default 0
)engine = innodb;
drop table if exists users;
create table users
(
user_id int unsigned not null primary key,
username varchar(32) not null
)engine = innodb;
insert into users_seq values (0);
delimiter #
create trigger users_before_ins_trig before insert on users
for each row
begin
declare id int unsigned default 0;
select next_seq_id + 1 into id from users_seq;
set new.user_id = id;
update users_seq set next_seq_id = id;
end#
delimiter ;
insert into users (username) values ('f00'),('bar'),('bish'),('bash'),('bosh');
select * from users;
select * from users_seq;
insert into users (username) values ('newbie');
select * from users;
select * from users_seq;
【讨论】: