2012-02-06 31 views
1

下面是一些示例代碼:ID仍遞增數據庫失敗後查詢

$sql = "INSERT INTO Users (Firstname,Surname) VALUES ('$firstname', '$surname')"; 

$stmt = sqlsrv_query($conn, $sql,array(), array("Scrollable" => SQLSRV_CURSOR_KEYSET)); 
if(!$stmt) 
{ 
die('Yu feiru!'); 
} 

有數據庫3列; ID,名字和姓氏。 ID是一個自動增量主鍵。我也有一個獨一無二的鑰匙。所以,現在我已經把這一切都放到了角度,都解釋了我的問題。

當我的表單完成後,它會進入上面的代碼執行頁面。現在,最初這是有效的,因爲它應該,所以現在我會在ID爲1的表中創建我的第一條記錄。現在,如果我要刷新此頁面,它將返回一個錯誤,這顯然是因爲我插入的是相同的名字,因爲它是一個獨特的關鍵,它不會工作,迄今如此好。

這是問題所在,如果我現在要返回到表單並提交新的細節,新記錄顯示ID爲3.所以問題在於每次運行查詢時,無論是成功與否,它會增加ID。因此,如果我要刷新頁面5次,那麼新記錄的ID將爲7.

編輯:請注意,正如我所說的,這只是示例代碼。我仍然沒有采取任何防範SQL注入的措施。無論如何,非常感謝您的建議。

+2

您的腳本很容易出現SQL注入。請確保您正確地轉義輸入。優先使用[Prepared Statements](準備陳述)(http://en.wikipedia.org/wiki/Prepared_statement)。 – TimWolla 2012-02-06 19:01:14

+0

你確定沒有插入重複記錄嗎?你的if語句也應該是'$ stmt === false',因爲'!'可以處理許多不同的事情。 – Henesnarfel 2012-02-06 19:02:57

+0

如果跳過號碼,自動遞增ID不關心。如果您刷新了300次並錯過了300個號碼,則無關緊要。對於一個非常注重細節的人來說,這可能會很麻煩,但如果ID被跳過,它確實沒有關係。 – 2012-02-06 19:03:29

回答

1

我可以給你一個可能的解決方案。但是:首先,你有很多理由要這樣做。一個ID的目的只是爲了確定,而不是提供一個可靠的唯一序列。如果你想要一個無縫的獨特序列,你可以用其他方式自己做。

話雖這麼說,這將觸發:

CREATE TRIGGER IdentityFixer 
    ON dbo.YourTable 
    AFTER INSERT 
AS 
BEGIN 
declare @NextID bigint 
set @NextID = (select MAX(MyID) from dbo.YourTable) 
DBCC CHECKIDENT ("dbo.YourTable", RESEED, @NextID); 
END 
GO 

會完美地解決您說的 「問題」(在Microsoft SQL Server)。你可以插入並失敗1000次,但你的ID仍然是無縫的。我不建議這樣做。

+0

謝謝,這是我正在尋找的答案。不過,我想我會按照你和其他人的建議去做,而不是爲它而煩惱。再次感謝... – Zizo47 2012-02-06 19:37:54

+0

沒問題! 祝你好運= - ) – Gaspa79 2012-02-06 19:42:08

0

您可以使用try/catch語句使用SQL事務,提交和回滾,這將解決所有問題。

+1

-1:事務不會改變自動增量列的行爲! – 2012-02-06 20:40:32

+0

如果沒有自動增量,這個工作還是我完全離開基地? – Sureround 2012-02-06 23:38:35

1

這是設計。無論是否發生COMMIT,每行的INSERT開始時都會分配IDENTITY列。任何後續的INSERT都會得到保證不衝突的號碼。任何或所有交易都可能失敗或被回滾。沒有這種能力,你將無法依靠IDENTITY列來同時操作。

我強烈質疑任何需要不間斷序列的設計目標。這種事情很少真正需要。我發現請求通常來自審計需求或來自某種喜歡假設某種行數/行數相關性的設計。通常,強大的審計功能可以在不依賴這樣的情況下實施。