2009-06-03 6 views
5

userpostにSOのようなタグを実装したいと思います。 tagId、title、countというカラムを持つtag_dataというテーブルがあります。私は、投稿とそれが使用するかもしれない多くのタグとの関係をリンクする別のテーブルを持っています。SQLで安全にカウント(フィールド)を更新

相続の問題は、私は現在のカウントを得るのですか、増減それを1で安全に保管してください。だから私は選択して更新する時間の間に他の接続/スレッドはそれを更新しませんか?

+0

新しいタグの挿入も保護する必要がありますか?それは通常、物事をかなり複雑にします。 –

+0

更新タグデータセットカウント=カウント+ @incrValここで、tagId = @タグID – spencer7593

答えて

13

私はあなたにも新たなカウントをしたいと仮定し、他のは賢明な、これは非常に簡単、ちょうど更新設定されたカウント=カウント数+ 1です。そうでない場合は

​​

:UPDATEであなたのDBサポート出力句(例えばSQL Serverの2K5または2K8)の場合

begin transaction 
update table 
    set counter=counter+1 
    where [email protected]; 
select counter 
    from table 
    where [email protected]; 
commit; 
+2

私は2つのことについて混乱しています。 update/selectが1つのステートメントなので、なぜトランザクションが必要なのでしょうか? 2つ目は、トランザクションが終了するまでデータベースをロックするように思われる他の2つの応答によって判断されます。なぜMikeyBは答えが悪いのですか?私はあなたの返信を読むが、何が起こるの?、他のスレッドはトランザクションを読むことはできますが、書き込みはできません。 –

+3

アップデートによって獲得されたXロックは、トランザクション*の間はヘルプ*であり、誰かがコミットするまでカウンターの読み取りや更新を禁止します。これにより、あなたが更新した実際の値を取得することを知っているあなたの選択を行うための保存場所が与えられます。声明は、このようにこっそりとあなたのアップデートが実行された時点で値を更新する2番目のスレッドを許可する、(通常の状態で)完了し、あなた'LL後にSは、選択によって得られたロックマイキーの場合 は* *ヘルプではありませんその更新を上書きします。したがって、「失われた更新」。 –

+0

良い答え。 @ Remus:トランザクション分離レベルを 'serializable'に設定するのはどうですか? –

-2

は擬似コード:

begin transaction 
A = select count from tag_data where tagId = TagId 
update tag_data set count = A+1 where tagId = TagId 
commit 
end transaction 

私は非常にお勧め上記のようなincrement_tag(TagId)と呼ばれるストアドプロシージャを作成します。

+1

同時スレッドが同じカウントを読み込み、インクリメントして更新しないようにするものはありません。これは、トランザクション処理における更新失われたケースの標準的な例です。最初の選択を少なくとも繰り返し可能な読み取り分離レベル(またはホールドロック)で保護する必要があります。 –

+0

SELECTステートメントをSELECT ... FOR UPDATEに変更することによって、この(非常に悪い)解決策を修正することもできます。これにより、この行のロックが取得されます。このロックは、このトランザクションがコミット/ロールバックするまで、更新/削除を実行する他のトランザクション、またはその行の別の更新の選択を保持します。 このカウンタを変更するすべてのコードでも、select for updateを使用するか、「update first then select」ルールを使用する必要があることを忘れないでください。 –

0

SET 1 +カウント=カウントは私見最も簡単な解決策..です

より一般的に

データを取得することができるという考え方、それを処理し、そこにその処理されている需要が結果を書き込む前に、何の根本的な変化もありませんしながら、あなたがスケーラブルなシステムも必要とするならば、処理は普通には合理的ではありません。あなたはもちろん、これを行うと、多くの環境でできる

はそれで逃げる並行性の問題は、システムが使用不能になる前に...しかし、これらのアプローチは、アプリケーションのscalaibilityと複雑さに厳しい制限を配置します。

より良いアプローチはunususal場合には、あなたが気に何かが変更をした場合には楽観的なルートを取ると、検出/再試行することです私見。

選択しない限り、処理...

UPDATE ... SETカウント= oldplus1 WHEREカウント=古いと...

... ...

... FROM AS古いカウントUPDATEは、データが変更されたと想定しているローカウントを返し、成功するまで再試行します。

関連する問題