次のトランザクションロックを達成する方法は?ロックトランザクションまたはテーブルヒントを使用したT-SQLの選択と更新
大きな単純化 - ステータスが「作成済み」、開始済み、完了済みの「タスク」の表があります。私はストアドプロシージャGetNext
を作成して、まだ開始されていないトップ1のタスクを取得したい(Created
ステータス)。
この手順では、タスクをStarted
とマークします。明らかに、2つのプロセスがこのプロシージャを呼び出して同じタスクを取得する状況を回避したいと思います。
このプロシージャは頻繁に呼び出されないため、パフォーマンスは問題ではないため、データを破損しない状態に保つことが重要です。
DECLARE @TaskId AS INT = (SELECT TOP 1 TaskId FROM tblTasks WHERE Status = 'Created')
UPDATE tblTasks
SET Status = 'Started'
WHERE TaskId = @TaskId
[... - Do something with @TaskId - not relevant]
OR:ようなものが必要私も、私はちょうど私の上にあるものよりも、そうではなく、更新タスクを受信したい
UPDATE tblTasks
SET Status = 'Started'
WHERE TaskId = (SELECT TOP 1 TaskId
FROM tblTasks
WHERE Status = 'Created')
:
は、だから私はこのような何かをしたいです
DECLARE @TaskIds AS TABLE(Id INT)
UPDATE tblTasks
SET Status = 'Started'
OUTPUT INSERTED.Id INTO @TaskIdS
WHERE TaskId = @TaskId
[... - Do something with @TaskIds - not relevant]
私が必要とするものを達成するには、選択+更新が必要であると仮定します。他のプロセスは、既存のプロセスが完了するまで最初の操作(選択)さえ実行しませんか?
他のプロセスがデータを読み取ることができるので、トランザクションのシリアライズ可能な分離レベルは十分ではありません。(更新がロックによって保持されているため)終了し、更新したばかりのデータを更新します。
私はそのテーブルがXLOCK
かHOLDLOCK
が役立つかもしれないヒントを感じるが、私は何の専門家だとMSのドキュメントは、私を怖がっ:
注意
SQL Serverクエリオプティマイザは、通常のための最適な実行計画を選択しているので経験豊富な開発者とデータベース管理者がヒントを最後の手段として使用することを推奨します。
(https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-tableから)
それでは、どのように私は2つのプロセスが一つの項目を更新しないことを確認してくださいともどのように私は1つのプロセスが他を実行している場合、後にその仕事を待って行いますことを確認してください最初に失敗するのではなく終わりますか?
サイドノート - 「order by」句を指定せずに「トップ1」を使用することは、「最初のレコードを取得する」という意味ではなく、単に「1レコードを取得する」ことを意味します。これは、データベース表が性質上順序付けされていないため、 'order by'節がなければ、リレーショナル・データベースは返されたレコードの順序を保証できません。 –
[このDan Guzmanの記事](http:// weblogs。sqlteam.com/dang/archive/2007/10/28/Conditional-INSERTUPDATE-Race-Condition.aspx) –