2012-07-24 126 views
1

我的問題很簡單,但答案可能會非常棘手。增量計數器mysql

我在PHP中,我想手動管理我的對象的唯一ID。 棘手的是管理原子性。我不想讓2個元素獲得相同的ID。

「元素」分組在「組」中。在每個組中,我希望元素ID從1開始,併爲該組中的每個插入增量增長。

我的第一個解決方案是在表中具有「組」一個「lastID」列:

CREATE TABLE groups (id INT AUTO_INCREMENT, lastId INT) 
CREATE TABLE elements (myId INT, multiple values ...) 

爲了避免具有相同ID的許多元素,我必須更新lastId並選擇它一個原子SQL查詢。

之後,一個檢索到,我有一個獨特的ID,不能再次被挑選,我可以插入我的元素。

我的問題是如何解決大膽的部分?我的數據庫是MyISAM引擎的MySQL,所以沒有事務支持。

UPDATE groups 
SET lastId = lastId + 1 
WHERE id = 42 

SELECT lastId 
FROM groups 
WHERE id = 42 

還有什麼東西比這兩個請求更原子嗎?

感謝

+0

爲什麼你不能使用自動增量ID?這正是它旨在解決的問題。 – 2012-07-24 21:04:11

+0

我需要有很多id序列,每個組 – 2012-07-24 21:30:49

回答

3
UPDATE groups SET lastId = last_insert_id(lastId + 1) 

,然後你可以用

SELECT last_insert_id() 

使用last_insert_id與參數將存儲的價值和回報它,當你再打它讓你的新的ID。
這種生成自動編號的方法最適合只有幾行的MyISAM表(MyISAM始終鎖定整個表)。它還具有在事務處理期間不鎖定表的好處(如果它是InnoDB表,將會發生這種情況)。

這是從MySQL manual

如果expr給出作爲參數傳遞給LAST_INSERT_ID(),由該函數返回的 參數的值和被記住作爲下一 值將被返回通過LAST_INSERT_ID()。這可以用來模擬 序列:

創建一個表來保存序列計數器和初始化:

CREATE TABLE sequence (id INT NOT NULL); 
INSERT INTO sequence VALUES (0); 

使用該表產生這樣的序列號:

UPDATE sequence SET id=LAST_INSERT_ID(id+1); 
SELECT LAST_INSERT_ID(); 

UPDATE語句增加nts序列計數器 並導致對LAST_INSERT_ID()的下一次調用返回更新的 值。 SELECT語句檢索該值。 mysql_insert_id()C API函數也可用於獲取該值。 請參見第21.8.3.37節「mysql_insert_id()」。

可以生成序列不調用LAST_INSERT_ID(),但 效用使用功能這樣的是,ID值是 保持在服務器作爲最後的自動生成的值。它 是多用戶安全的,因爲多個客戶端可以發出UPDATE 語句,並使用SELECT語句 (或mysql_insert_id())獲取它們自己的序列值,而不會影響其他 客戶端生成自己的序列值或受其影響。

+0

這不是原子的。例如,如果有兩個連續的UPDATE,然後是兩個連續的SELECT,則只有在同一連接上執行兩個連續更新時,纔會返回相同的標識 – 2012-07-24 21:30:04

+1

。它與你通常使用last_insert_id的方式類似(你必須在插入之後立即使用它,但是從其他連接插入它是安全的)。 – Vatev 2012-07-24 21:43:14

+0

您的意思是,如果兩個不同的用戶同時運行更新,那麼last_insert_id無法爲每個用戶返回相同的值?如果這是肯定的,這是一個很好的答案,但我看到MyISAM鎖定了桌子!如果用戶更新鎖定表,會發生什麼?我的桌子有數百萬條記錄! – 2012-07-24 21:49:24

0

我假設你的MySQL安裝也有支持事務的InnoDB引擎。您只需要更改表格的引擎類型。

+0

其實我的開發環境是在InnoDB上強制外鍵檢查。而且我的生產環境在MyISAM上,沒有FK。 – 2012-07-24 21:37:53

+0

您是否可以不更改生產數據庫表中的引擎?你真的應該匹配你的兩個環境,因爲MyISAM和InnoDB有完全不同的行爲。 – 2012-07-24 21:41:46

+0

不,我不行。我依賴於我的提供者。我在開發環境中使用innoDB來強制外鍵檢查,因爲這會顯示出MyISAM所沒有的錯誤。 – 2012-07-24 21:46:20

3

一個選項是讓你使用漂亮的MyISAM功能,讓每個組的auto_increment值遞增。

CREATE UNIQUE INDEX ON elements_ix1元素(的groupId,身份識別碼)

身份識別碼INT NOT NULL AUTO_INCREMENT

這是更多的 「原子」 比任何涉及更新一個單獨的表。請注意,這隻適用於MyISAM,而不適用於InnoDB。


摘自http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html

的MyISAM注

對於MyISAM表,可以在多列索引的二次列中指定AUTO_INCREMENT。在這種情況下,AUTO_INCREMENT列的生成值計算爲MAX(auto_increment_column)+ 1 WHERE prefix = given-prefix。當您想要將數據放入有序組時,這非常有用。

+0

這看起來很不錯,值得+1。但我不確定我想將我的應用程序行爲粘貼到數據庫引擎。我希望它可以移植到另一個引擎。 – 2012-07-24 21:34:02

+0

其實我的開發環境是在InnoDB上強制外鍵檢查。而且我的生產環境在MyISAM上,沒有FK。 – 2012-07-24 21:37:06