ストアドプロシージャを使用してSQL Server(2008)テーブルにデータを挿入するC#アプリケーションがあります。私はこれを行うためにマルチスレッドを使用しています。ストアドプロシージャがスレッド内から呼び出されています。現在、私のストアドプロシージャは、データの挿入中に「tablock」を使用しています。このコードを実行すると、「トランザクション(プロセスID)が別のプロセスのロックリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行してください。」というエラーが発生します。
誰かがこれの解決策を手伝ってくれませんか?
これは、2つのSQL Serverプロセスが同じリソースにアクセスしているが、順序が異なる場合に発生します。したがって、どちらもデッドロックである他のプロセスを待つことになります。
これを防ぐ方法はいくつかあります。
with (nolock)
ロックヒントを使用します。例えば。 Proc1がtable1をロックしてからtable2をロックし、Proc2がtable2をロックしてからtable1をロックすると、問題が発生する可能性があります。この問題を回避するために、どちらかのプロシージャを書き換えて同じ順序でロックを取得できます。
クエリをTRY CATCHブロックにカプセル化し、エラー番号(ロックに関連する)をキャッチできます。
次に、特定の数まで再試行を自動化できます。したがって、次のようなことを行います。
DECLARE @RetryNo Int = 1
,@RetryMaxNo Int = 5;
WHILE @RetryNo < @RetryMaxNo
BEGIN
BEGIN TRY
-- put your query that generates locks here....
SELECT @RetryNo = @RetryMaxNo;
END TRY
BEGIN CATCH
IF ERROR_NUMBER() IN (1204, 1205, 1222)
BEGIN
SET @RetryNo += 1;
-- it will wait for 10 seconds to do another attempt
WAITFOR DELAY '00:00:10';
END
ELSE
THROW;
END CATCH
END
[〜#〜] updlock [〜#〜] などのテーブルヒントを使用することもできます。
更新または挿入するフィールドを確認してください。このフィールドには非クラスター化インデックスがあります。利用できない場合は、最初にこのテーブルにこのフィールドの非クラスター化インデックスを作成し、作成後に以下の手順に従います。
テーブルを右クリックして、プロパティを選択します。
プロパティの右側のパネルでオプションを選択します。
[ロック]タブで、[ページロックを許可]を[False]にし、[行ロックを許可]を[True]にして、[OK]を押します。
これはS Kumar DubeyによるMSDNのソリューションです
SPの実行:SP_LOCK結果で、SPID、DBID、OBJID、INDID、TYPE、RESOURCE、MODE、STATUSを取得します。ステータス列を確認します。待機が表示されている場合は、そのSPIDを強制終了します。特定のSPIDを強制終了するにはSPを実行します:65を強制終了します(65はSPIDです)。
この問題を解決するには、SQLサーバー管理者である必要があります。
Lockオブジェクトから使用できます
static object _lock = new object();
public static void _main()
{
lock (_lock)
{
_bulkcopy(myData);
}
}
public static void _bulkcopy(DataTable dt)
{
try
{
using (var connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("DBConnection")))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = 100;
bulkCopy.DestinationTableName = "dbo.MyTable";
try
{
bulkCopy.WriteToServer(dt);
}
catch (Exception)
{
transaction.Rollback();
connection.Close();
}
}
transaction.Commit();
}
}
catch { }
}
デッドロックのリスクを最小限に抑える方法でデータベースモジュールを設計する必要があります。これを行う方法に関するいくつかの役立つヒントを次に示します。アプリケーションがすべての共有オブジェクトに同じ順序でアクセスすることを確認します。