情况就是这样。我有一个带有发票号(int)的主表和许多带有相关数据的表。发票时,我在主表中增加发票号,然后将附加数据和发票号放在其余表中。
由于所有事务都在事务中(READ COMMITED),因此在提交此事务之前,所有更改都不会被写入。
我知道如果某个其他交易同时使用相同的发票号并首先提交,我将会出错。我可以用新号码重试,但这是最好的方法吗?
如果有很多并发长发票(包含大量数据的交易),可能会有很多次重试。
我正在考虑快速预订发票号码或锁定它但我不知道如何......
答案 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。只需确保只有一种方法可以访问自定义密钥表。
但这听起来不太可扩展/高效。