2009-04-11 77 views
0

這是我當前數據庫的摘錄(改表名字更容易理解):作用域/複合代理鍵在MySQL

Pet(ownerFK, id, name, age) 
Owner(id, name) 

哪裏id始終是一個代理鍵,用auto_increment創建。

我希望代理鍵Pet.id被作爲「作用域」的Pet.ownerFK或換句話說,有一個複合鍵[ownerFk, id]作爲我的最小鍵。我想表的行爲是這樣的:

INSERT Pet(1, ?, "Garfield", 8); 
INSERT Pet(1, ?, "Pluto", 12); 
INSERT Pet(2, ?, "Mortimer", 1); 

SELECT * FROM Pet; 
    RESULT: 
    Pet(1, 1, "Garfield", 8) 
    Pet(1, 2, "Pluto", 12) 
    Pet(2, 1, "Mortimer", 1) 

我目前使用這個feature of MyISAM其中「你可以在一個多列索引中第二列指定AUTO_INCREMENT在這種情況下,對於AUTO_INCREMENT列生成的值計算方式爲MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。當你想將數據放入有序組時,這很有用。「

但是,由於各種(也許是顯而易見的)原因,我想從MyISAM切換到InnoDB,因爲我需要在某些地方進行事務處理。

有什麼辦法可以實現這種效果InnoDB

我在這個問題上發現了一些帖子,其中許多人建議在插入之前寫入鎖定表。我對此並不是很熟悉,但是對於這個問題,這不會是一次表大小寫的修改嗎?如果可能的話 - 我有一個Owner.current_pet_counter作爲助手字段,我寧願寫安全交易(我從未做過)。

所以其他可接受的解決辦法是...

其實我也不需要「作用域」 ID是實際鍵的一部分。我的實際數據庫設計使用了一個單獨的「永久鏈接」表,它使用了這個'功能'。我目前使用它作爲缺失事務的解決方法。我想下面的替代:

Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId) 
Owner(id, name, current_pet_counter) 

START TRANSACTION WITH CONSISTENT SNAPSHOT; 
SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id; 
INSERT Pet(?, :owner_id, @new, "Pluto", 21); 
UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id; 
COMMIT; 

我還沒有在MySQL的交易/ transactionvars工作,所以我不知道會不會有這一個嚴重的問題。 注意:我不想重複使用曾經給寵物一次的id。這就是爲什麼我不使用MAX()此解決方案是否有任何警告?

回答

1

我不這麼認爲。如果您真的必須擁有該模式,您可以使用事務來選擇MAX(id)WHERE ownerFK,然後選擇INSERT。

我非常懷疑這個模式有一個很好的理由,主鍵現在也是關鍵的事實,這可能會使數據庫理論家不高興。

通常情況下,你會希望'id'真的是一個真正的主鍵,ownerFK用於分組,如果你需要它,還有一個單獨的'等級'列,以每個擁有者的特定順序,以及一個UNIQUE索引(ownerFK,rank)。

+0

我明白了你的觀點。我的實際數據庫設計有點不同,我也不需要它成爲主鍵的一部分。我用目前正在評估的解決方案更新了這個問題。 – 2009-04-11 16:34:48