我有一个SQL服务器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();
}
}
}
答案 0 :(得分: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 Pattern。 http://msdn.microsoft.com/en-us/library/system.idisposable.aspx