@@IDENTITY與SCOPE_IDENTITY()

在一條 INSERT、SELECT INTO 或大容量複製語句完成後,@@IDENTITY 中包含語句生成的最後一個標識值。若是語句未影響任何包含標識列的表,則 @@IDENTITY 返回 NULL。若是插入了多個行,生成了多個標識值,則 @@IDENTITY 將返回最後生成的標識值。若是語句觸發了一個或多個觸發器,該觸發器又執行了生成標識值的插入操做,那麼,在語句執行後當即調用 @@IDENTITY 將返回觸發器生成的最後一個標識值。若是對包含標識列的表執行插入操做後觸發了觸發器,而且觸發器對另外一個沒有標識列的表執行了插入操做,則 @@IDENTITY 將返回第一次插入的標識值。出現 INSERT 或 SELECT INTO 語句失敗或大容量複製失敗,或者事務被回滾的狀況時,@@IDENTITY 值不會恢復爲之前的設置。服務器

      若是語句和事務失敗,它們會更改表的當前標識,從而使標識列中的值出現不連貫現象。即便未提交試圖向表中插入值的事務,也永遠沒法回滾標識值。例如,若是因 IGNORE_DUP_KEY 衝突而致使 INSERT 語句失敗,表的當前標識值仍然會增長。函數

     @@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 是類似的函數,由於他們都返回插入到表的 IDENTITY 列的最後一個值。spa

     @@IDENTITY 和 SCOPE_IDENTITY 能夠返回當前會話中的全部表中生成的最後一個標識值。可是,SCOPE_IDENTITY 只在當前做用域內返回值,而 @@IDENTITY 不限於特定的做用域。code

     IDENT_CURRENT 不受做用域和會話的限制,而受限於指定的表。IDENT_CURRENT 能夠返回任何會話和任何做用域中爲特定表生成的標識值。事務

     @@IDENTITY 函數的做用域是執行該函數的本地服務器上的當前會話。此函數不能應用於遠程或連接服務器。若要得到其餘服務器上的標識值,請在遠程服務器或連接服務器上執行存儲過程,並使(在遠程或連接服務器的環境中執行的)該存儲過程收集標識值,並將其返回本地服務器上的發出調用的鏈接。

     如下示例向包含標識列 (LocationID) 的表中插入一行,並使用 @@IDENTITY 顯示新行中使用的標識值:

作用域

USE  AdventureWorks;
GO
-- Display the value of LocationID in the last row in the table.
SELECT   MAX (LocationID)  FROM  Production.Location;
GO
INSERT   INTO  Production.Location (Name, CostRate, Availability, ModifiedDate)
VALUES  ( ' Damaged Goods ' 5 2.5 GETDATE ());
GO
SELECT   @@IDENTITY   AS   ' Identity ' ;
GO
-- Display the value of LocationID of the newly inserted row.
SELECT   MAX (LocationID)  FROM  Production.Location;
GO



補充:
  咱們要慎用@@IDENTITY,緣由是 @@IDENTITY 它老是獲取最後一條變動數據的自增字段的值,
 而忽略了進行變動操做所在的範圍約束。好比,我有表 A 和表 B 兩個表,如今我在表 A 上定義了一個Insert觸發器,當在表 A 中插入一條數據時,自動在表 B 也插入一條數據。此時,你們注意,有兩個原子操做:在A中插入一條數據, 接着在B中隨後插入一條數據。
 
   如今咱們想下,假設上面表 A 和表 B 都有IDENTITY自增域,那麼咱們在表 A 插入一條數據後,使用了 SELECT @@IDENTITY 輸出時,輸出的究竟是 A 仍是 B 的自增域的值呢?  答案很明顯,是誰最後插入就輸出誰,那麼就是 B 了。因而,我本意是想獲得 A 的自增域值,結果獲得了 B 的自增域值,一隻 BUG 隨之誕生,搞很差還會影響到整個系統數據的混亂。
 
   所以,對於這種狀況,建議你們慎用 @@IDENTITY,而儘可能採用 SCOPE_IDENTITY() 函數替換之。SCOPE_IDENTITY() 也是獲得最後一條自增域的值,可是它是僅限在一個操做範圍以內,而不@@IDENTITY 是取全局操做的最後一步操做所產生的自增域的值的。it

相關文章
相關標籤/搜索