2011-10-01 79 views
2

我有屬於各個用戶的項目表:如何保證表格值只在表格行的一個子集中唯一?

PROJECT_ID,owner_user_id,PROJECT_NAME

我不需要project_names是全局唯一的表,所以使得PROJECT_NAME唯一沒有幫助。我只想阻止用戶在INSERT或UPDATE上創建重複的project_names。

一旦INSERT/UPDATE,我只想檢查是否已經有一個project_name屬於特定的owner_user_id,並且如果它已經存在,則INSERT/UPDATE應該失敗。

我可以使用SELECT首先檢查用戶項目中是否存在project_name,然後只在select返回沒有結果時才執行INSERT/UPDATE。但是這是多線程的,另一個線程可以在執行SELECT之後但在INSERT/UPDATE之前立即插入相同的project_name。把這一切都放到一個交易中感覺就像是矯枉過正。是否有一個查詢可以執行此操作?

+0

是owner_user_id和project_name之間的一個可能的關係嗎?我的意思是一個用戶可以有不同的project_name? – punit

+0

@punit是的,正好 – jpeskin

回答

1

你可以在兩列添加UNIQUE constraint爲一對:

alter table your_table add unique (owner_user_id, project_name) 

這將確保project_name值是每個用戶唯一的。你需要看看你的collation set up,以確保你的project_name值進行比較,而不考慮大小寫。或者你可以在命中數據庫之前將項目名稱標準化爲標題大小寫。

除非必須手動維護數據完整性,否則請儘可能讓數據庫處理您的約束。

0

這確實需要在交易中。您需要檢索一些信息(「哪些名稱已被使用?」),然後採取行動(「如果我的名字沒有被使用,然後使用它」)。這必須以原子方式完成。

正如您已經正確猜測,如果插入檢查後沒有原子地發生,就會出現競態條件。

這是交易的目的。

0

您可以在這兩個字段添加唯一的約束

CONSTRAINT C_UNICITY UNIQUE (owner_user_id, project_name) 

每次嘗試插入或更新記錄其中存在重複的時候,你會得到一個SQL錯誤

0
$result = mysql_query("select * from Project where owner_user_id='1';");   
if (mysql_affected_rows()==0) { 
    $result = mysql_query("insert into Project (projectname) values ('pojectname');"); 
0

根據數據庫參照完整性違規爲你拋出錯誤陷阱通常不是UI驗證的首選形式 - 無論如何你通常都希望獲得更高抽象層的東西。但沒有什麼特別的「矯枉過正」關於使用交易和UNIQUE約束來自由地保護您的數據和您的用戶一樣多。

+0

您能詳細說明爲什麼使用數據庫完整性違規不是UI驗證的首選形式嗎?我發現「畝太短」的答案相當優雅。你是說這種驗證不應該在數據庫約束中「隱藏」,而是在業務邏輯代碼中更明顯,還是有其他原因?關於交易的「矯枉過正」:這個應用程序否則不需要它們,所以我試圖通過InnoDB保留MyIASM的速度優勢。 – jpeskin

+0

對於初學者來說,來自數據庫的錯誤消息通常不是爲最終用戶設計的。通常,除了字節串的任何組合以外,還有什麼構成可接受的項目名稱,表格還沒有關鍵字。你真的瀕臨過度使用innodb嗎? – dkretz

相關問題