2013-05-14 187 views
19

假設:INSERT操作是否會導致死鎖?

  • 我使用REPEATABLE_READ或SERIALIZABLE事務隔離(鎖會保留我每次訪問行)
  • 我們正在談論的多個線程同時訪問多個表。

我有以下問題:

  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權限; - 插入權限.id = 100
  • INSERT INTO companies(name,permission_id)VALUES('Nintendo',100); - 插件companies.id = 200

我刪除公司如下:

  • SELECT permission_id FROM公司WHERE ID = 200; - 返回permission_id = 100
  • DELETE FROM companies WHERE id = 200;
  • DELETE FROM permissions WHERE id = 100;

在上例中,INSERT鎖定順序爲[permissions,companies],而DELETE鎖定順序爲[companies,permissions]。有沒有辦法解決這個例子爲REPEATABLE_READSERIALIZABLE隔離?

+0

插入,選擇和刪除是不會導致死鎖定義爲單個用戶(在單個事務中)的場景。 – 2013-05-14 03:07:25

+0

@CleverIdeaWidgetry,我澄清了這個問題,以反映我們正在討論多線程和表的事實。 – Gili 2013-05-14 03:10:47

+0

您的基本問題的答案是「可以嗎?」是的 - 正如其他人所說的。是否有一些障礙阻止你自己測試你的場景? – 2013-05-14 03:31:22

回答

22

通常,所有的修改都可能導致死鎖,而選擇不會(稍後再獲取)。所以

  1. 不,你不能忽略這些。
  2. 根據您的數據庫和設置,您可以稍微忽略選擇,但其他選項會導致死鎖。

你甚至都不需要多個表。

創建僵局的最好辦法是做同樣的事情在不同的順序。

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 

第二場:

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不應該死鎖,但在某些數據庫會因爲它使用了鎖干擾持續讀。這只是蹩腳的數據庫引擎設計。如果你使用快照隔離

SQL Server將不會鎖定在一個SELECT。 Oracle &我認爲Postgres永遠不會鎖定SELECT(除非您有FOR UPDATE,這明顯保留了更新)。

所以基本上我認爲你有一些不正確的假設。我想我已經證明:

  1. 更新可能導致死鎖
  2. 刪除可能導致死鎖
  3. 插入可能導致死鎖
  4. 你不需要多個表
  5. 需要多於一個會話

你只需要聽取我的意見SELECT;)但它將取決於y我們的數據庫和設置。

+0

首先,感謝您的正派回答正確的問題:)其次,我爲您的評論添加了第三個問題。請參閱最新的問題。 – Gili 2013-05-14 04:00:17

+0

這看起來不會起作用。由於FK的引用,您無法在公司之前刪除權限。 – LoztInSpace 2013-05-14 04:09:31

+0

我已更正問題#3。請再試一次。 – Gili 2013-05-14 04:12:21

0

讓我們假設你有兩個關係AB和兩個用戶XY。表A被寫由用戶X鎖定和表B被寫由Y.鎖定,那麼如果使用的用戶X和Y.

Select * from A,B 

所以顯然Select操作既可以在下面的查詢會給你一個死鎖如果涉及多個表的連接操作是其中的一部分,則會導致死鎖。通常插入和刪除操作涉及單個關係。所以他們不會造成僵局。

+0

請假定所有操作都涉及多個表(如示例中所示),因爲顯然,如果不這樣做,您就不會發生死鎖。爲此,哪些操作可能導致死鎖,哪些操作不能。到目前爲止,您已經演示了'SELECT' **如何導致死鎖。我們來討論其餘的問題。 – Gili 2013-05-14 03:07:12

+0

如果在關係A和關係B之間存在外鍵約束,則A和B分別被用戶X和Y鎖定,則可能會發生死鎖。 – Deepu 2013-05-14 03:15:29

+0

你還沒有回答我的問題。我詢問**所有** SQL操作,而不僅僅是'SELECT'。我主要對'INSERT'感興趣,但我希望你也討論所有其他的操作類型。 – Gili 2013-05-14 03:19:03

1

除了LoztInSpace的回答,inserts可能會導致死鎖,即使沒有deletesupdates的存在。您只需要一個唯一的索引和一個顛倒的操作順序。

實施例中的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 2016-06-09 12:19:12

+1

我認爲最簡單(但並非總是可行)的解決方案是在插入之前對行進行排序。 – 2016-06-09 12:41:55

+0

爲什麼會在線程2提交時導致死鎖,而不是約束違例和回滾? – 2017-11-20 11:23:35