将密钥分发到事务中的多个表的最佳方法

时间:2011-02-14 13:15:26

标签: sql-server tsql transactions locking

情况就是这样。我有一个带有发票号(int)的主表和许多带有相关数据的表。发票时,我在主表中增加发票号,然后将附加数据和发票号放在其余表中。

由于所有事务都在事务中(READ COMMITED),因此在提交此事务之前,所有更改都不会被写入。

我知道如果某个其他交易同时使用相同的发票号并首先提交,我将会出错。我可以用新号码重试,但这是最好的方法吗?

如果有很多并发长发票(包含大量数据的交易),可能会有很多次重试。

我正在考虑快速预订发票号码或锁定它但我不知道如何......

4 个答案:

答案 0 :(得分:0)

如果您使用auto_incrementing发票ID,您的交易引擎应该为您处理此问题。

即。假设当前最高发票为2,则通过向该表添加行来插入新发票。调用LAST_INSERT_ID()将为您提供刚刚在该发票主表中插入的行的ID,即3.如果同时另一个另一个事务开始,它将获得数字4.您的事务引擎是智能的足以不重复分配ID。然后,您可以使用此ID标记辅助表中的所有数据,而不必担心它会被双重分配。

答案 1 :(得分:0)

这样做:

BEGIN TRANSACTION

INSERT INTO YourHeaderTable  (col1, col2,..) values (...)---where PK is identity
SELECT @newID=SCOPE_IDENTITY()

INSERT INTO Table2 VALUES (@newID,...)  --use the @newID from YourHeaderTable  
INSERT INTO Table3 VALUES (@newID,....) --use the @newID from YourHeaderTable  
...

COMMIT

您将永远不会遇到具有相同新ID的两个并发用户的问题。数据库将为您管理ID和并发用户的增量,使此错误免费且可靠。你试图做的除此之外的任何事情不仅仅是重新发明轮子,而且会更复杂,更不可靠,更容易出错。

答案 2 :(得分:0)

使用IDENTITY列 - 这将保证唯一值。您可以(如果您使用的是SQL Server 2005+)使用初始OUTPUT查询的INSERT子句来捕获为您的发票行生成的ID值。如果要插入多个发票,则应从插入中捕获其他列,以唯一标识用于在其他表中插入相关行的发票。

答案 3 :(得分:0)

好吧,如果你绝对不能有漏洞(根据身份),那么你将需要锁定你的自定义id /种子表行,直到你100%确定所有的插入都已提交。但是,您还需要确保对此记录的任何其他并发访问也是SERIALIZABLE隔离级别。

BEGIN TRAN
SELECT NextId FROM myKeysTable
WITH (XLOCK, SERIALIZABLE)
WHERE myTablePKName = 'SomeId'
...

这将在行上保留一个独占锁定,防止其他读取(以及SERIALIZABLE条件)。

或者,请查看sp_getapplock - 示例here。只需确保只有一种方法可以访问自定义密钥表。

但这听起来不太可扩展/高效。