0

我有一个 SQL Server CLR 存储过程,用于检索大量行,然后执行一个过程并更新另一个表中的计数。

这是流程:

选择 -> 处理 -> 更新计数 -> 将所选行标记为已处理

该过程的本质是它不应将同一组数据计算两次。并且使用 GUID 作为参数调用 SP。

因此,我保留了当前正在处理的 GUID 列表(在 SP 中的静态列表中),并停止执行以相同参数对 SP 的后续调用,直到当前正在处理的调用完成。

当进程在 finally 块中完成时,我有删除 GUID 的代码,但它并非每次都有效。在某些情况下(例如用户取消 SP 的执行),SP 退出时没有调用 finally 块,也没有从列表中删除 GUID,因此后续调用会无限期地等待。

你们能给我一个解决方案,以确保无论如何都会调用我的 finally 块或任何其他解决方案,以确保在任何给定时间只有一个 ID 正在处理中。

这是删除了处理位的代码示例

[Microsoft.SqlServer.Server.SqlProcedure]
public static void TransformSurvey(Guid PublicationId)
{
    AutoResetEvent autoEvent = null;
    bool existing = false;

    //check if the process is already running for the given Id
    //concurrency handler holds a dictionary of publicationIds and AutoresetEvents
    lock (ConcurrencyHandler.PublicationIds)
    {
        existing = ConcurrencyHandler.PublicationIds.TryGetValue(PublicationId, out autoEvent);
        if (!existing)
        {
            //there's no process in progress. so OK to start
            autoEvent = new AutoResetEvent(false);
            ConcurrencyHandler.PublicationIds.Add(PublicationId, autoEvent);
        }
    }
    if (existing)
    {
        //wait on the shared object
        autoEvent.WaitOne();
        lock (ConcurrencyHandler.PublicationIds)
        {
            ConcurrencyHandler.PublicationIds.Add(PublicationId, autoEvent); //add this again as the exiting thread has removed this from the list
        }
    }
    try
    {
        // ... do the processing here..........

    }
    catch (Exception ex)
    {
        //exception handling
    }
    finally
    {
        //remove the pubid          
        lock (ConcurrencyHandler.PublicationIds)
        {
            ConcurrencyHandler.PublicationIds.Remove(PublicationId);
            autoEvent.Set();
        }
    }

}
4

1 回答 1

1

在更高级别包装代码是一个很好的解决方案,另一个选项可能是 IDisposable 的 using 语句。

public class SQLCLRProcedure : IDisposable
{
     public bool Execute(Guid guid)
     {
           // Do work
     }
     public void Dispose()
     {
           // Remove GUID
           // Close Connection
     }
}

using (SQLCLRProcedure procedure = new SQLCLRProcedure())
{
  procedure.Execute(guid);
}

这未在编译器中验证,但通常称为 IDisposable 模式。 http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

于 2013-01-31T04:01:57.377 回答