2013-05-14 7 views
19

:私はREPEATABLE_READまたはSERIALIZABLEトランザクション分離を使用していますINSERT操作でデッドロックが発生する可能性がありますか?仮定

  • は、我々は同時に複数のテーブルにアクセスする複数のスレッドを話している
  • (ロックは毎回私が行にアクセスを保持します)。

私は、次の質問がある:

  1. は、デッドロックが発生するINSERT操作のため、それは可能ですか?もしそうなら、デッドロックがどのように起こるかを示す詳細なシナリオを提示してください(例えば、スレッド1はこれを行い、スレッド2はそれを行います...、デッドロック)。
  2. ボーナスポイントの場合:他のすべての操作について同じ質問に答えます(SELECT、UPDATE、DELETEなど)。

UPDATE: スーパーボーナスポイント3.:どのように私は次のシナリオでは、デッドロックを避けることができますか?

考えるテーブル:

  • 権限次のように私は新しい会社を作成[id BIGINT PRIMARY KEY]
  • 企業[id BIGINT PRIMARY KEY, name VARCHAR(30), permission_id BIGINT NOT NULL, FOREIGN KEY (permission_id) REFERENCES permissions(id))

  • INSERT INTOを権限。 - inserts permissions.id = 100
  • INSERT INTOの会社(名前、許可ID)VALUES( 'Nintendo'、100); - インサートcompanies.id = 200

次のように私は会社を削除します。

  • SELECTは、ID = 200の企業からpermission_id。 - 戻り値permission_id = 100
  • id = 200の会社から削除します。
  • 権限からの削除WHERE id = 100;

上記の例では、INSERTロック順序は[permissions、companies]ですが、DELETEロック順序は[companies、permissions]です。 REPEATABLE_READまたはSERIALIZABLEアイソレーションのこの例を修正する方法はありますか?

+0

(単一のトランザクションで)単一のユーザーとして定義されたシナリオ、挿入選択し、削除がデッドロックが発生するつもりはありません。 –

+0

@CleverIdeaWidgetryは、私たちは、複数のスレッドやテーブルの話をしているという事実を反映するために質問を明らかにしました。 – Gili

+0

あなたの基本的な質問に対する答えは「できますか?」他人が言ったように、はいです。自分のシナリオをテストするのを妨げる障害がいくつかありますか?それは私の特定のデータベースでのデッドロックせずに働くかもしれないという理由だけで –

答えて

22

一般に、すべての変更はデッドロックを引き起こす可能性があり、選択はできません(後で行います)。したがって

  1. いいえあなたは無視できません。
  2. データベースと設定によってselectを無視することはできますが、それ以外の場合はデッドロックが発生します。

複数のテーブルは必要ありません。

デッドロックを作成する最良の方法は、同じことを別の順序で行うことです。

SQL Serverの例:

create table A 
(
    PK int primary key 
) 

セッション1:

begin transaction 
insert into A values(1) 

セッション2:

begin transaction  
insert into A values(7) 

セッション1:

delete from A where PK=7 

セッション2:

delete from A where PK=1 

デッドロックが発生します。だから、証明書の挿入&がデッドロックする可能性があります。

更新は似ています。

セッション1:

begin transaction  
insert into A values(1) 
insert into A values(2) 
commit 

begin transaction 
update A set PK=7 where PK=1 

セッション2:

begin transaction 
update A set pk=9 where pk=2  
update A set pk=8 where pk=1 

セッション1:

update A set pk=9 where pk=2 

デッドロック!

SELECTはデッドロックしないでください。ただし、使用するロックによって一貫性のある読み取りが妨げられるため、一部のデータベースではSELECTが使用されます。しかし、それはちょっとしたデータベースエンジンの設計です。

SNAPSHOT ISOLATIONを使用すると、SQL ServerはSELECTをロックしません。オラクル&私はPostgresが決してSELECTにロックしないと思います(もしあなたがFOR UP UPATEを持っていなければ、とにかくアップデートのために予約されています)。

だから、基本的には間違った仮定がいくつかあると思います。私は私が証明したと思う:

  1. アップデートが
  2. 削除がデッドロックにあなたが必要性を行う複数のテーブル
  3. を必要としない
  4. 挿入を引き起こす可能性がデッドロックを引き起こす可能性がデッドロックを引き起こす可能性があります2つ以上のセッション

私はSELECTで単語を取る必要がありますが、yに依存します私たちのDBと設定。

+0

まず、質問に答える優しさをお持ちいただきありがとうございます:)第二に、私はあなたのレビューのために3番目の質問を追加しました。更新された質問をご覧ください。 – Gili

+0

それはうまくいかないようです。 FKが参照している会社の前で許可を削除することはできません。 – LoztInSpace

+0

質問#3を修正しました。もう一度お試しください。 – Gili

0

ABの2つの関係と、2人のユーザーXYという2つの関係があるとします。表Aは、ユーザXによってロックされた書き込みされており、表Bは、そうはっきりSelect操作ができるユーザーのXとY

Select * from A,B 

の両方で使用される場合は、次のクエリはあなたに死んでロックを与えるY.による書き込みをロックされます複数の表を含む結合操作がその一部であると、デッドロックが発生します。通常、挿入操作と削除操作には1つのリレーションが含まれます。だから彼らはデッドロックを引き起こさないかもしれない。

+0

すべての操作に複数のテーブルが含まれていると仮定してください(この例で示すように)。デッドロックが発生していないことは明らかです。そのために、どの操作がデッドロックを引き起こす可能性があり、それができないのか。これまでに、 'SELECT' **がどのようにデッドロックを引き起こすかを実証しました。残りについて議論しましょう。 – Gili

+0

関係AとB、AとBの間の外部キー制約は、それぞれのユーザーのXとYによってロックされている場合は、デッドロックが発生する可能性があります。 – Deepu

+0

あなたは私の質問に答えていません。私は** SELECT **だけでなく、**すべての** SQL操作について尋ねています。私は主に 'INSERT'に興味がありますが、他のすべての操作タイプについても議論することを期待しています。 – Gili

1

LoztInSpaceの回答に加えて、insertsは、deletesまたはupdatesがなくてもデッドロックを引き起こす可能性があります。あなたが必要とするのは、ユニークなインデックスと逆の操作命令だけです。 Oracleで

例:

create table t1 (id number); 
create unique index t1_pk on t1 (id); 

--thread 1 : 
insert into t1 values(1); 
--thread 2 
insert into t1 values(2); 
--thread 1 : 
insert into t1 values(2); 
--thread 2 
insert into t1 values(1); -- deadlock ! 
+0

そしてその解決策は何ですか? – Akvel

+1

私は、(常に可能なわけではないが)最も簡単な解決策は、挿入する前に行をソートすることだと思います。 –

+0

これはなぜ制約違反ではなくデッドロックを引き起こし、スレッド2のコミットでロールバックするのでしょうか? –

関連する問題