如果我在多个同时查询中使用 IsolationLevel.Snapshot 进行事务查询,SELECT @@IDENTITY 将返回啥?
Posted
技术标签:
【中文标题】如果我在多个同时查询中使用 IsolationLevel.Snapshot 进行事务查询,SELECT @@IDENTITY 将返回啥?【英文标题】:What is the SELECT @@IDENTITY will return if I have Transactional Query with IsolationLevel.Snapshot in multiple and simultaneous query?如果我在多个同时查询中使用 IsolationLevel.Snapshot 进行事务查询,SELECT @@IDENTITY 将返回什么? 【发布时间】:2015-08-04 06:24:12 【问题描述】:我有多个应用程序通过多个事务访问表,我希望这些多个应用程序/事务能够让执行该事务的应用程序相应地插入每个 主键/身份。由于某种原因,我不能使用 SCOPE_IDENTITY,这就是为什么我最后的排序是使用 @@IDENTITY。对于事务查询,我为每个事务实现了 IsolationLevel.Snapshot 以避免阻塞。
现在我的问题是,在这种情况下,每笔交易是否会正确并相应地返回 @@IDENTITY。
例如。我同时执行了三个查询:
Transactional1 查询插入,预期返回标识 100; Transactional2 查询插入,预期返回标识 102; Transactional3 查询插入,预期返回标识 103;它会像这样相应地返回身份吗? 这是我的目标
事务 1 - 100 事务2 - 102 事务 3 - 103或者它可能会发生这样的事情? 这是我害怕发生的事情
事务 1 - 102 事务2 - 103 事务 3 - 101这个现有的触发器是 SCOPE_IDENTITY 确实返回身份的原因,即使我的代码和查询中有 SCOPE_IDENTITY。
ALTER trigger [dbo].[CustomerAddressesInsertVIds] on [dbo].[CustomerAddresses]
instead of insert
as
begin
set nocount on
insert into [dbo].[CustomerAddresses]
([CustomerID], [AddressTypeID], [CustomerAddressID], [AddressNameType], [Name], [ContactID], [Address1], [Address2], [Address3], [City], [County], [State], [Country], [Zip], [Phone1], [Phone2], [Fax1], [Fax2], [CreateDate], [CreateUser], [MaintenanceDate], [MaintenanceUser], [LastOrderDate], [DeleteOnDate], [SyncStatus], [SyncDate], [SyncUser], [ERPID], [CreateCustomerID], [CreateContactID], [MaintenanceCustomerID], [MaintenanceContactID], [Active], [Deleted], [LockUser], [LockSessionID], [LockDate], [InUse], [AddressTypeVId], [CustomerVId])
select
coalesce([CustomerID], (select [CustomerID] from [dbo].[Customers] where [CustomerVId]=inserted.[CustomerVId])), coalesce([AddressTypeID], (select [AddressTypeID] from [dbo].[AddressTypes] where [AddressTypeVId]=inserted.[AddressTypeVId])), [CustomerAddressID], [AddressNameType], [Name], [ContactID], [Address1], [Address2], [Address3], [City], [County], [State], [Country], [Zip], [Phone1], [Phone2], [Fax1], [Fax2], [CreateDate], [CreateUser], [MaintenanceDate], [MaintenanceUser], [LastOrderDate], [DeleteOnDate], [SyncStatus], [SyncDate], [SyncUser], [ERPID], [CreateCustomerID], [CreateContactID], [MaintenanceCustomerID], [MaintenanceContactID], [Active], [Deleted], [LockUser], [LockSessionID], [LockDate], [InUse], coalesce([AddressTypeVId], (select [AddressTypeVId] from [dbo].[AddressTypes] where [AddressTypeID]=inserted.[AddressTypeID])), coalesce([CustomerVId], (select [CustomerVId] from [dbo].[Customers] where [CustomerID]=inserted.[CustomerID]))
from inserted
end
【问题讨论】:
我建议使用SCOPE_IDENTITY()
而不是其他任何东西(如@@IDENTITY
)来获取新插入的标识值。 See this blog post for an explanation as to WHY
@marc_s,我在问题中提到我不能使用 SCOPE_IDENTITY,这就是我使用 @@IDENTITY 的原因。
如果您能详细说明为什么 SCOPE_IDENTITY
不起作用,我们或许可以提供其他建议。例如。 OUTPUT
子句 可能 是比使用任何独立身份函数更好的选择 - 但是我们如何知道您何时只是对为什么不能使用最明显的解决方案感到害羞呢?
我不能使用 SCOPE_IDENTITY 因为我现在正在处理的现有表有那个不返回身份的触发器,即使我的查询中有 SCOPE_IDENTITY,所以我发货了使用 @ @IDENTITY 代替。根据您的回答,这是否意味着我别无选择,只能更改该触发器以返回身份,而不是仅仅为了获得它而发明想法?
【参考方案1】:
documentation 中涵盖了大部分重要细节:
@@IDENTITY
和SCOPE_IDENTITY
返回当前会话中任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY
只返回当前范围内的值;@@IDENTITY
不限于特定范围。
还有关于 @@IDENTITY
如何返回意外值的详细信息 - 但这些都与(如预期的那样)范围而不是其他会话相关。
如果您正在处理其他会话,则该集合中唯一与您有关的函数是IDENT_CURRENT
。
当然,如果您的代码还处理 触发器(创建嵌套范围),这些触发器也使用标识值操作表(导致 @@IDENTITY
返回“错误”值)并且您出于某种原因,我已经排除了SCOPE_IDENTITY
,那么你就不走运了。
【讨论】:
您好,我知道您发布的文档。您提到了处理触发器,这正是我现在的问题,这就是为什么我想出我发布的这个想法来解决我的问题。我现在正在处理的现有表具有不返回身份的触发器,即使我的查询中有 SCOPE_IDENTITY,所以我转而使用 @@IDENTITY。根据您的回答,这是否意味着我别无选择,只能更改该触发器以返回 @IDENTITY 而不是为了获得身份而发明想法? @JrTabuloc - 不,如果您想检索触发器产生的标识值,那么您可以使用@@IDENTITY
,这应该可以。
现有触发器不返回任何身份。为了清楚起见,我在我的问题中发布了触发器。可能我需要更改该触发器以返回身份。顺便说一句,该触发器在我工作之前就已经存在,这就是为什么我害怕更改它,因为我不是数据库专家,无法确定如果我将其更改为返回身份会产生什么影响。
@JrTabuloc - 不,您不需要更改触发器。 @@IDENTITY
可用于从触发器外部获取标识值。
那么您是在告诉我,我在问题中发布的第二种情况永远不会发生吗? 我害怕发生的事以上是关于如果我在多个同时查询中使用 IsolationLevel.Snapshot 进行事务查询,SELECT @@IDENTITY 将返回啥?的主要内容,如果未能解决你的问题,请参考以下文章