假设,我想模仿自动递增在MySQL/InnoDB的模拟自动递增在MySQL/InnoDB的
条件
- 使用MySQL/InnoDB的
- ID字段不具备的独特索引,也不是一个PK
是否有可能模仿只使用程序逻辑,没有表级别锁定。 谢谢。
假设,我想模仿自动递增在MySQL/InnoDB的模拟自动递增在MySQL/InnoDB的
条件
是否有可能模仿只使用程序逻辑,没有表级别锁定。 谢谢。
使用序列表和触发器 - 是这样的:
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;
用一行和一列存储下一个id值创建另一个表。然后在原始表上创建一个插入触发器,用于增加第二个表中的值,抓取它,并将其用于第一个表上的ID列。你需要小心你的选择和更新方式,以确保它们是原子的。
本质上,您正在模拟MySQL中的Oracle sequence
。它会导致序列表中的单行锁定,所以这可能会使它不适合你正在做的事情。
ETA:
另一个类似,但也许效果更好的选择是将创建第二个“序列”表中,仅仅有一个自动增量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。确保你的表支持事务处理,或者序列中的漏洞没有问题。
顺序表需要有id作为自动增量PK