假设:
我有以下问题:
INSERT
操作是否可能导致死锁?如果是,请提供详细的方案,演示如何发生死锁(例如,线程1执行此操作,线程2执行此操作那,...,死锁)。更新: 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锁定顺序是[permissions,companies],而DELETE锁定顺序是[companies,permissions]。有没有办法为REPEATABLE_READ
或SERIALIZABLE
隔离修复此示例?
答案 0 :(得分:28)
通常所有修改都会导致死锁,而选择则不会(稍后再说)。所以
您甚至不需要多个表格。
创建死锁的最佳方法是以不同的顺序执行相同的操作。
SQL Server示例:
create table A
(
PK int primary key
)
第1节:
begin transaction
insert into A values(1)
第二节:
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
第二节:
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永远不会死锁,但在某些数据库上它会因为它使用的锁会干扰一致的读取。这只是糟糕的数据库引擎设计。
如果使用SNAPSHOT ISOLATION,SQL Server将不会锁定SELECT。甲骨文&我认为Postgres永远不会锁定SELECT(除非你有FOR UPDATE,无论如何都明确保留了更新)。
所以基本上我认为你有一些不正确的假设。我想我已证明:
你只需要接受SELECT;),但这取决于你的数据库和设置。
答案 1 :(得分:5)
除了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 !
答案 2 :(得分:0)
我们假设您有两个关系A
和B
以及两个用户X
和Y
。表A由用户X进行WRITE锁定,表B由Y进行WRITE锁定。如果用户X和Y都使用,则以下查询将为您提供死锁。
Select * from A,B
很明显,如果涉及多个表的连接操作是其中的一部分,Select
操作可能会导致死锁。通常,插入和删除操作涉及单个关系。所以他们可能不会造成僵局。