我创建了一个动态创建 SQL 代码的应用程序。
该应用程序应该对一些由条形码识别的生产订单进行分组,并将其合并为一个提货订单。
为了实现这一点,我需要写入 SQL Server 数据库:
通常我会在 SQL Server 中创建一个标识列,然后使用
select scope_identity()
查询新插入的标识,但我需要多次使用我的标识符。
这是我的应用程序当前生成的 SQL 代码:
set xact_abort on
BEGIN TRAN
declare @MultiOrderReference as integer
set @MultiOrderReference = (select max(Reference) from PickReference ) + 1
insert into PickReference (Reference, Barcode, Amount) values (@MultiOrderReference, '0068518000', 1)
insert into PickReference (Reference, Barcode, Amount) values (@MultiOrderReference, '0068548000', 4)
insert into PickReference (Reference, Barcode, Amount) values (@MultiOrderReference, '0068550000', 8)
select @MultiOrderReference as Reference
commit tran
这将插入具有公共标识符的行,然后将标识符返回给应用程序。
这在大多数情况下都有效,考虑到这些都是非常小的事务(快),它可能总是有效,但据我了解,它不是线程安全的。因此,如果另一个用户同时运行该应用程序,我想理论上两个应用程序实例可以使用相同的公共标识符。
有办法防止这种情况吗?或者我错了,这实际上是线程安全的,因为我使用的是“begin tran -> commit tran”?
看起来你应该只使用
SEQUENCE
。
CREATE SEQUENCE dbo.PickId AS int
START WITH 1;
然后获取它的值。
SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;
DECLARE @MultiOrderReference int = NEXT VALUE FOR dbo.PickId;
INSERT INTO PickReference (Reference, Barcode, Amount)
VALUES
(@MultiOrderReference, '0068518000', 1),
(@MultiOrderReference, '0068548000', 4),
(@MultiOrderReference, '0068550000', 8);
COMMIT;
SELECT @MultiOrderReference AS Reference;
如果您真的想坚持使用现有代码,那么您需要添加锁定提示:
SERIALIZABLE
和UPDLOCK
。您还应该在 Reference
上添加索引。
set @MultiOrderReference = isnull((
select max(Reference)
from PickReference with (serializable, updlock)
), 0) + 1;