3

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

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

谢谢

4

2 回答 2

4

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

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

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

这隐含在它自己的事务中,并将保证唯一值。


编辑

我最初的评论是,这在插入多条记录时不起作用,相反,您需要单独遍历源记录,一次插入一条。

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

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) 和插入所有新记录之间的表中读取。)

于 2011-10-31T15:44:06.570 回答
1

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

于 2011-10-31T17:29:22.887 回答