INSERT操作会导致死锁吗?

时间:2013-05-14 02:42:12

标签: sql insert deadlock

假设:

  • 我正在使用REPEATABLE_READ或SERIALIZABLE事务隔离(每次访问行时都会保留锁)
  • 我们谈论的是多个线程同时访问多个表。

我有以下问题:

  1. INSERT操作是否可能导致死锁?如果是,请提供详细的方案,演示如何发生死锁(例如,线程1执行此操作,线程2执行此操作那,...,死锁)。
  2. 奖励积分:为所有其他操作回答相同的问题(例如,SELECT,UPDATE,DELETE)。
  3. 更新: 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权限; - 插入permissions.id = 100
    • INSERT INTO公司(name,permission_id)VALUES('Nintendo',100); - 插入companies.id = 200

    我删除公司如下:

    • SELECT permission_id FROM公司WHERE id = 200; - 返回permission_id = 100
    • DELETE FROM公司WHERE id = 200;
    • DELETE FROM权限WHERE id = 100;

    在上面的示例中,INSERT锁定顺序是[permissions,companies],而DELETE锁定顺序是[companies,permissions]。有没有办法为REPEATABLE_READSERIALIZABLE隔离修复此示例?

3 个答案:

答案 0 :(得分:28)

通常所有修改都会导致死锁,而选择则不会(稍后再说)。所以

  1. 不,你不能忽视这些。
  2. 根据您的数据库和设置,你可以稍微忽略select,但其他人会给你死锁。
  3. 您甚至不需要多个表格。

    创建死锁的最佳方法是以不同的顺序执行相同的操作。

    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,无论如何都明确保留了更新)。

    所以基本上我认为你有一些不正确的假设。我想我已证明:

    1. 更新可能会导致死锁
    2. 删除可能会导致死锁
    3. 插入可能会导致死锁
    4. 您不需要多个表
    5. 执行需要多个会话
    6. 你只需要接受SELECT;),但这取决于你的数据库和设置。

答案 1 :(得分:5)

除了LoztInSpace的回答,即使没有insertsdeletes存在,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)

我们假设您有两个关系AB以及两个用户XY。表A由用户X进行WRITE锁定,表B由Y进行WRITE锁定。如果用户X和Y都使用,则以下查询将为您提供死锁。

Select * from A,B

很明显,如果涉及多个表的连接操作是其中的一部分,Select操作可能会导致死锁。通常,插入和删除操作涉及单个关系。所以他们可能不会造成僵局。

相关问题