2010-07-20 69 views
2

假設,我想模仿自動遞增在MySQL/InnoDB的模擬自動遞增在MySQL/InnoDB的

條件

  1. 使用MySQL/InnoDB的
  2. ID字段不具備的獨特索引,也不是一個PK

是否有可能模仿只使用程序邏輯,沒有表級別鎖定。 謝謝。

回答

2

使用序列表和觸發器 - 是這樣的:

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; 
1

用一行和一列存儲下一個id值創建另一個表。然後在原始表上創建一個插入觸發器,用於增加第二個表中的值,抓取它,並將其用於第一個表上的ID列。你需要小心你的選擇和更新方式,以確保它們是原子的。

本質上,您正在模擬MySQL中的Oracle sequence。它會導致序列表中的單行鎖定,所以這可能會使它不適合你正在做的事情。

ETA:

另一個類似,但也許效果更好的選擇是將創建第二個「序列」表中,僅僅有一個自動增量PK列,沒有其他數據。讓您的插入觸發器在該表中插入一行,並使用生成的ID填充原始表中的ID。然後要麼觸發器或另一個進程週期性地刪除序列表中的所有行來清理它。

2
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。確保你的表支持事務處理,或者序列中的漏洞沒有問題。

0

順序表需要有id作爲自動增量PK