English 中文(简体)
将键分配到事务中多个表的最佳方法
原标题:Best approach to distribute a key into multiple tables within a transaction

事实就是这样。我有一个带有发票编号(int)的主表和许多带有相关数据的表。当开具发票时,我会增加主表中的发票编号,然后将额外的数据和发票编号放在其他表中。

由于所有内容都在一个事务中(READ COMMITED),所以在提交该事务之前,不会以物理方式编写所有更改。

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

如果有许多并发的长发票(具有大量数据的事务),则可能会有多次重试。

我正在想办法快速预订发票号码或锁定它,但我不知道如何。。。。

最佳回答

如果您使用的是auto_increating发票id,那么您的事务引擎应该为您处理这一问题。

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

问题回答

请执行以下操作:

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和并发用户的增量,从而使此错误免费且可靠。除此之外,你试图做的任何事情都不仅仅是重新发明轮子,而是更复杂、更不可靠、更容易出错。

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

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

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

这将在行上保持一个独占锁,防止其他读取(并附带SERIALIZABLE限制条件)。

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

但这听起来不太具有可扩展性/性能。





相关问题
How to write this T-SQL WHERE condition?

I ve got two tables: TableA Col1 Col2 TableB Col3 Col4 I want to join them together: SELECT * from TableA join TableB ON (...) Now, in place of ... I need to write an expression ...

Customer and Order Sql Statement

TSQL query to select all records from Customer that has an Order and also select all records from customer that does not have an Order. The table Customer contains a primary key of CustomerID. The ...

Recommended way of querying multiple Versioned tables

Have a win 2003 box with MSSQL 2005 running on it. There is a database which is populated every morning with new/modified SalesOrder made the previous day. The database has several tables: SalesOrder, ...

update duplicate record

I have a table with the following fields Id Name IsPublic i need to write a sql query that updates IsPublic to false where name has a duplicate. Only one of the duplicates should have IsPublic = ...

Define variable to use with IN operator (T-SQL)

I have a Transact-SQL query that uses the IN operator. Something like this: select * from myTable where myColumn in (1,2,3,4) Is there a way to define a variable to hold the entire list "(1,2,3,4)"? ...

Selecting records during recursive stored procedure

I ve got a content management system that contains a hierarchical structure of categories, with sub-categories subject to different ordering options at each level. Currently, that s retrieved by a (...

热门标签