@@ IDENTITY并触发问题

时间:2011-10-31 15:39:26

标签: sql sql-server triggers identity-column

我遇到了一个众所周知的触发器问题和@@ IDENTITY。 我创建了一个新的审核表和一个触发器,用于在其上插入审核行。 我们使用的是使用@@ IDENTITY的软件,这会导致与触发器插入新行时生成的Id发生冲突。 我无法访问使用@@ IDENTITY的代码。

我需要关于如何通过自己生成身份价值的想法。我不能使用GUID,因为订单对我很重要。 如果我用默认值GETDATE()的datetime列替换Id列,它是否保证它是唯一的?

谢谢

2 个答案:

答案 0 :(得分:2)

GETDATE()不会是唯一的。它的准确性使得可以同时提供多个近似并发事件。

如果您强制生成自己的身份值,以免干扰@@ IDENTITY,那么您可以执行以下操作...

INSERT INTO
  myTable (
    id,
    field1,
    field2
  )
SELECT
  (SELECT ISNULL(MAX(id), 0) FROM myTable WITH(TABLOCKX)) + 1,
  @p1,
  @p2

这隐含在它自己的交易中,并将保证唯一的价值。


修改

我原来的评论是,当插入多个记录时,这将无效,而您需要单独遍历源记录,一次插入一个。

但是,以下示例可能适合您处理数据SET ...

WITH
  sorted_data AS
(
  SELECT
    ROW_NUMBER() OVER (ORDER BY field1) AS set_id,   -- DO NOT include a PARTITION here
    *
  FROM
    inserted
)
INSERT INTO
  myTable (
    id,
    field1,
    field2
  )
SELECT
  (SELECT ISNULL(MAX(id), 0) FROM myTable WITH(TABLOCKX)) + set_id,
  @p1,
  @p2
FROM
  sorted_data

这将为每一行生成唯一的ID,并且对使用相同代码的并发进程是安全的。

修改

我添加了WITH(TABLOCKX)以防止其他进程在更新时从表中读取。这可以防止并发进程建立相同的MAX(id),然后尝试在新记录中插入重复的id。

(单个查询结构已经阻止了记录在被读取之后被更改,但是没有阻止其他进程从正在读取的MAX(id)和插入的所有新记录之间的表中读取。)

答案 1 :(得分:1)

我知道您可能无法更改内容,但问题是该软件使用的是@@ IDENTITY,这不在范围内。插入任何表格将更改@@ IDENTITY。该软件应该使用函数scope_identity()代替。