0

大量の行セットを取得するために使用されるSQLサーバーCLRストアドプロシージャがあり、プロセスを実行して別のテーブルのカウントを更新します。

フローは次のとおりです。

選択 -> プロセス -> カウントの更新 -> 選択した行を処理済みとしてマーク

このプロセスの性質上、同じデータ セットを 2 回カウントすることはできません。また、SP は GUID を引数として呼び出されます。

そのため、現在処理中の GUID のリストを (SP の静的リストに) 保持し、現在処理中の GUID が終了するまで、同じ引数を使用して SP への後続の呼び出しの実行を停止します。

プロセスが最終ブロックで終了したときに GUID を削除するコードがありますが、毎回機能しているわけではありません。最終ブロックを呼び出さずに SP が終了し、リストから GUID を削除せずに SP が終了するインスタンス (ユーザーが SP の実行をキャンセルした場合など) があるため、後続の呼び出しは無期限に待機し続けます。

いつでも1つの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 に答える