并行插入/更新期间的死锁

时间:2016-12-26 12:44:40

标签: java sql-server hibernate stored-procedures apache-camel

我是MS SQL Server的新手,我试图通过递增出现计数器(+1)来更新记录,如果数据丢失或我刚刚插入计数器值为零' 0'。

此外,我的应用程序以 parallel 运行,以处理数据数组a []的每个元素。并行处理数组时,SQL Server会为此引发死锁。虽然我设置了事务隔离级别,但是在表上发生了同样的死锁。我的应用程序是用Java / Camel / Hibernate编写的。

存储过程:

IF(@recordCount = 0 OR @recordCount > 1 )
BEGIN
        IF(@chargeAbbreviation IS NOT NULL)
        BEGIN
            set transaction isolation level READ COMMITTED;
            begin transaction;

                    UPDATE  dbo.SLG_Charge_Abbreviation_Missing_Report WITH (UPDLOCK, HOLDLOCK)
                        SET     dbo.SLG_Charge_Abbreviation_Missing_Report.Occurrence_Count+=1,dbo.SLG_Charge_Abbreviation_Missing_Report.ModifiedAt=GETDATE()
                        WHERE   dbo.SLG_Charge_Abbreviation_Missing_Report.Jurisdiction_ID = @jurisdictionId AND
                                UPPER(dbo.SLG_Charge_Abbreviation_Missing_Report.Charge_Abbreviation) = @chargeAbbreviation AND 
                                (UPPER(dbo.SLG_Charge_Abbreviation_Missing_Report.Statute_Code) = @statuteCode OR (dbo.SLG_Charge_Abbreviation_Missing_Report.Statute_Code IS NULL AND @statuteCode IS NULL)) AND
                                dbo.SLG_Charge_Abbreviation_Missing_Report.Product_Category_id = @productCategoryId
                IF(@@ROWCOUNT = 0)
                BEGIN
                INSERT INTO dbo.SLG_Charge_Abbreviation_Missing_Report VALUES(@OriginalChargeAbbreviation,@jurisdictionId,@OriginalStatuteCode,@productCategoryId,GETDATE(),GETDATE(),1);
                END
            commit
        END
    SELECT TOP 0 * FROM dbo.SLG_Charge_Mapping

END

1 个答案:

答案 0 :(得分:2)

您似乎正在尝试使用某些版本的Sam Saffron's upsert method

要在使用holdlock / serializable时利用Key-Range Locking,您需要有一个涵盖查询中列的索引。

如果您没有覆盖此查询的内容,可以考虑创建一个这样的内容:

create unique nonclustered index ux_slg_Charge_Abbreviation_Missing_Report_jid_pcid_ca_sc
  on dbo.slg_Charge_Abbreviation_Missing_Report (
      Jurisdiction_id 
    , Product_Category_id
    , Charge_Abbreviation
    , Statute_Code
    );

我不认为这一行:set transaction isolation level read committed;在这种情况下对你有所帮助。

set nocount on;
set xact_abort on;
if(@recordCount = 0 or @recordCount > 1 )
  begin;
    if @chargeAbbreviation is not null
      begin;
        begin tran;
            update camr with (updlock, serializable)
              set  camr.Occurrence_Count  = camr.Occurrence_Count + 1
                 , camr.ModifiedAt        = getdate()
              from dbo.slg_Charge_Abbreviation_Missing_Report as camr
            where camr.Jurisdiction_id            = @jurisdictionId 
              and camr.Product_Category_id        = @productCategoryId
              and upper(camr.Charge_Abbreviation) = @chargeAbbreviation 
              and (
                  upper(camr.Statute_Code)        = @statuteCode 
                    or (camr.Statute_Code is null and @statuteCode is null)
              ) 
        if @@rowcount = 0
          begin;
          insert into dbo.slg_Charge_Abbreviation_Missing_Report values
            (@OriginalChargeAbbreviation,@jurisdictionId
            ,@OriginalStatuteCode,@productCategoryId
            ,getdate(),getdate(),1);
          end;
        commit tran
      end;
    select top 0  from dbo.slg_Charge_Mapping;
end;

注意:holdlockserializable相同。

与上述解决方案相关的链接: