在交易中使用@@ IDENTITY是否安全?

时间:2016-09-08 19:52:22

标签: sql sql-server tsql coldfusion transactions

我正在阅读关于将最后一个身份值输入数据库的不同方法的this回答。

根据我的理解,@@IDENTITY通常是非常糟糕的主意,因为它可能会返回一个与您预期不同的标识 - 例如最近创建的标识值通过触发器。

但是如果您的代码在交易中会怎样?

例如,这是我正在做的事务的简化版本(使用ColdFusion):

<cftransaction>
    <cfquery name="queryInsertA" datasource="source">
        INSERT INTO tableA (columnName) VALUES (value)
    </cfquery>
    <cfquery name="queryInsertB" datasource="source">
        INSERT INTO tableB (fkey_tableA, columnName) VALUES (@@IDENTITY, value)
    </cfquery>
</cftransaction>

因为“If a transaction is successful, all of the data modifications made during the transaction are committed and become a permanent part of the database”,这是否意味着它还会阻止使用@@IDENTITY时可能出现的问题?还是我误解了交易的行为?

7 个答案:

答案 0 :(得分:14)

您链接的答案已经解释了@@IDENTITY的主要问题:范围。如果您的插入触发另一个插入,您将获得意外的身份。交易不会改变任何内容。

答案 1 :(得分:2)

如果要将最后一个标识值插入表中,请使用Ident_current()函数。

   Select ident_current ('your table name')

你也可以使用scope_identity(),它只会带来一个tablein的特定值。

  Select scope_identity()

答案 2 :(得分:1)

您不需要@@ Identity,也不需要2个单独的查询。使用Scope_identity()函数实现完整性并使其成为同一连接的一部分。查询 - 就像这样。

<cfquery name="putUser" datasource="#dsn#">
SET NOCOUNT ON
INSERT INTO users(username, email)
VALUES 
('#usersname#','#email#' )
SELECT  SCOPE_IDENTITY() AS newId FROM users
SET NOCOUNT OFF 
</cfquery>

<cfoutput>#putUser.newID#</cfoutput>

这将是完全安全的,但是像所有数据库事务一样,它仍然会遇到死锁,因此调整仍然很重要。

CFTRANSACTION适用于多个数据库操作,其中也可能涉及某些CF逻辑,但让数据库锁定和事务系统通过将它们保持在一起为您工作。

答案 3 :(得分:1)

您还可以使用result的{​​{1}}属性。如果查询执行标识的INSERT或ID的自动增量值,则结构中将返回名为cfquery的键。

GENERATEDKEY

请记住,这只是CF9及更高版本。

答案 4 :(得分:0)

您可以使用序列并在插入过程中使用它,如下所示:

CREATE SEQUENCE Testseq  
    START WITH 1  
    INCREMENT BY 1 ;

使用以下查询访问序列:

SELECT NEXT VALUE FOR Testseq;

答案 5 :(得分:0)

简化:

如果

你知道你在数据库系统中一无所有,这意味着,没有其他用户或进程在同一时间运行,没有其他事务在运行,你使用它时有绝对的ZERO活动,我的意思是它,ZERO ACTIVITY,那么,好吧......

<强> ELSE

不,不!如果上面列出的任何内容确实在您的交易正在运行时发生,那么您最终会得到错误的身份。

答案 6 :(得分:-2)

这取决于在事务实例化的同时运行的其他内容。如果与可以插入新标识值的事务无关的表上存在触发器,则您当前所在的事务范围将不会保护您。

例如,假设我创建了一个更新Table_A并在其中插入记录的SPROC。此表上有一个标识字段,每次插入新记录时,该字段将增加该表中的ID值。在我的SPROC中,我创建了一个事务并将我的插入放在事务中。插入后,我将@@ IDENTITY的值存储在同一事务中的变量中。

现在我还有另一个表Table_B,它有自己的标识值,但是这个表是触发器维护的。如果我正在执行我的SPROC以在Table_A中插入一行,并且在此更新期间Table_B也通过触发器更新,则当我检索@@ IDENTITY的值时,它实际上可能会给我创建的ID的值表_而不是Table_A。

您绝对应该在存储过程中使用事务,但最好选择插入的表的MAX(ID)来检索您创建的ID,而不是@@ IDENTITY。