【问题标题】:SQL Server stored procedure Isolate transaction has been cancelledSQL Server 存储过程 Isolate 事务已被取消
【发布时间】:2021-10-26 11:42:20
【问题描述】:

我有一个更新表的存储过程。当存储过程同时从不同的 PC 执行时,我会收到此错误。

System.Exception: System.Data.SqlClient.SqlException (0x80131904): La transaction d'isolement d'instantané a étébandnée en raison d'un conflit de mise à jour。 Vous ne pouvez pas utiliser l'isolement d'instantané pour accéder à la table 'dbo.Journee' directement 或indirectement dans la base de données 'PlanningGestion' afin de mettre à jour, de supprimer ou d'insérer la ligne modifiée ou supprimée par une autre 交易。 Réexécutez la transaction ou changez le niveau d'isolement pour l'instruction de mise à jour/suppression

是否可以指定系统需要等到第一个存储过程执行结束后再启动新的?作为先进先出。

或者我必须使用其他方式来做到这一点?

PS:我的存储过程从子查询更新

update Journee 
set UVGlobalJournee = (select 
                           case
                               when max(E.UVGlobale) is null
                                   then 0 
                                   else max(E.UVGlobale) 
                           end
                       from 
                           Examen E 
                       inner join 
                           IT_Journee_Examen IT on E.IdExamen = IT.IDEXAMEN 
                       where 
                           Journee.IdJournee = IT.IDJOURNEE) 
where Test = '1'  
  and Journee.IdJournee = @IdJournee

【问题讨论】:

标签: sql-server stored-procedures


【解决方案1】:

如果您使用已提交的读取快照(READ_COMMITTED_SNAPSHOT 数据库选项),则设置 TRANSACTION ISOLATION LEVEL 无效。

而是将READCOMMITTEDLOCK 表提示添加到正在更新的表中。

请注意,除非您在所有其他表格中也使用 READCOMMITTEDLOCK,否则您仍然会出现读取偏差

create or alter procedure name_of_your_procedure AS
begin

update Journee WITH (READCOMMITTEDLOCK)
set UVGlobalJournee = (select 
                           case
                               when max(E.UVGlobale) is null
                                   then 0 
                                   else max(E.UVGlobale) 
                           end
                       from 
                           Examen E 
                       inner join 
                           IT_Journee_Examen IT on E.IdExamen = IT.IDEXAMEN 
                       where 
                           Journee.IdJournee = IT.IDJOURNEE) 
where Test = '1'  
  and Journee.IdJournee = @IdJournee

end

【讨论】:

  • 也许我可以用不同的方式写查询。如果我做的变量表包含我的子查询的所有值,那么执行 cursor rto update line by line 。也许我会保护交易不?
  • 不,这行不通,不知道你为什么认为它会。您应该在 SNAPSHOT 上 read up 并更新冲突
【解决方案2】:

您可以使用显式事务,在您的过程中具有已提交的读取隔离级别。 假设程序代码只是问题的内容,它会是这样的:

create or alter procedure name_of_your_procedure AS
begin
set transaction isolation level read committed
begin transaction
update Journee 
set UVGlobalJournee = (select 
                           case
                               when max(E.UVGlobale) is null
                                   then 0 
                                   else max(E.UVGlobale) 
                           end
                       from 
                           Examen E 
                       inner join 
                           IT_Journee_Examen IT on E.IdExamen = IT.IDEXAMEN 
                       where 
                           Journee.IdJournee = IT.IDJOURNEE) 
where Test = '1'  
  and Journee.IdJournee = @IdJournee
commit transaction
end

如果在启用 RCSI 的数据库上运行,则将此过程的开头更改为:

set transaction isolation level snapshot

并同时执行它,您将在问题上得到相同的错误。提交读取后,我无法收到该错误。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多