我有一个 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();
}
}
}