SQL CLR убедитесь, что блок наконец выполнен

У меня есть хранимая процедура CLR на SQL-сервере, которая используется для получения большого набора строк, а затем для выполнения процесса и обновления счетчика в другой таблице.

Вот поток:

выберите -> обработать -> обновить счетчик -> пометить выбранные строки как обработанные

Суть процесса заключается в том, что он не должен учитывать один и тот же набор данных дважды. И SP вызывается с GUID в качестве аргумента.

Поэтому я держу список идентификаторов GUID (в статическом списке в SP), которые в данный момент находятся в процессе, и останавливаю выполнение для последующих вызовов SP с тем же аргументом до тех пор, пока не завершится текущий процесс.

У меня есть код для удаления GUID, когда процесс завершается в блоке finally, но он не работает каждый раз. Существуют случаи (например, когда пользователь отменяет выполнение SP), когда SP выходит из системы, не вызывая блок finally и не удаляя GUID из списка, поэтому последующие вызовы ожидают бесконечно долго.

Не могли бы вы, ребята, дать мне решение, чтобы убедиться, что мой блок finally будет вызываться независимо от того, какое или какое-либо другое решение, чтобы убедиться, что в данный момент выполняется только один идентификатор.

Вот пример кода с удаленными битами обработки

[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();
        }
    }

}

1 ответ

Обертывание кода на более высоком уровне - это хорошее решение, другим вариантом может быть оператор using с IDisposable.

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

Другие вопросы по тегам