为什么要删除一个表语句,将一个select语句锁定到同一个表--SQL Server

时间:2013-12-25 10:38:33

标签: sql sql-server sql-server-2012 deadlock

我有一个用Spring 3.0编写的应用程序,并使用SQL Server 2012 Enterprise作为RDS。

我一直在我的DAO操作上使用@Transactional,在这种特殊情况下

    @Transactional
    public void removeAll(String token) {

        cacheDao.delete(token);

    }

    public ClassSome getValue(String id) {
        return cacheDao.getValue(id);
    }

我的删除操作是事务性的,但未指定选择操作。这是导致死锁发生在下面的原因吗?

最近我遇到了数据库中的死锁。主要是上面的这两个操作会出现死锁。

我不明白单个表上的查询如何相互死锁。这是DBA给我的一个示例死锁列表:

<deadlock-list>
<deadlock victim="process1180f5d498">
  <process-list>
   <process id="process1180f5d498" taskpriority="0" logused="0" waitresource="OBJECT: 6:1266103551:0 " waittime="2141" ownerId="1748561" transactionname="SELECT" lasttranstarted="2013-12-25T11:24:17.140" XDES="0x117ce7ba40" lockMode="S" schedulerid="30" kpid="4424" status="suspended" spid="87" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2013-12-25T11:24:17.140" lastbatchcompleted="2013-12-25T11:24:17.137" lastattention="1900-01-01T00:00:00.137" clientapp="Microsoft SQL Server JDBC Driver" hostname="xxxx" hostpid="0" loginname="xxxx" isolationlevel="read committed (2)" xactid="1748561" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="74" sqlhandle="0x02000000e0a92205aebcb9dd3f38539312f56b0c41af55990000000000000000000000000000000000000000">
select token, type, value from cache where token=@P0 and type=@P1     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@P0 varchar(8000),@P1 varchar(8000))select token, type, value from cache where token=@P0 and type=@P1                    </inputbuf>
   </process>
   <process id="process117d375c38" taskpriority="0" logused="0" waitresource="OBJECT: 6:1266103551:29 " waittime="2141" ownerId="1748560" transactionname="implicit_transaction" lasttranstarted="2013-12-25T11:24:17.140" XDES="0xf68c743a8" lockMode="X" schedulerid="64" kpid="9628" status="suspended" spid="96" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2013-12-25T11:24:17.140" lastbatchcompleted="2013-12-25T11:24:17.140" lastattention="1900-01-01T00:00:00.140" clientapp="Microsoft SQL Server JDBC Driver" hostname="xxxx" hostpid="0" loginname="xxx" isolationlevel="read committed (2)" xactid="1748560" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="74" sqlhandle="0x0200000023b477359eec278e4060e11f3a1c194cbed41cc10000000000000000000000000000000000000000">
delete cache where token=@P0 and type=@P1     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@P0 varchar(8000),@P1 varchar(8000))delete cache where token=@P0 and type=@P1                    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <objectlock lockPartition="0" objid="1266103551" subresource="FULL" dbid="6" objectname="xxxx.dbo.cache" id="lock10034ef580" mode="X" associatedObjectId="1266103551">
    <owner-list>
     <owner id="process117d375c38" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process1180f5d498" mode="S" requestType="wait"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="29" objid="1266103551" subresource="FULL" dbid="6" objectname="xxxx.dbo.cache" id="lock1011729e00" mode="IS" associatedObjectId="1266103551">
    <owner-list>
     <owner id="process1180f5d498" mode="IS"/>
    </owner-list>
    <waiter-list>
     <waiter id="process117d375c38" mode="X" requestType="wait"/>
    </waiter-list>
   </objectlock>
  </resource-list>
</deadlock>
</deadlock-list>

编辑#1

-- Results for: 
    SELECT  i.name, i.allow_row_locks, i.allow_page_locks
    FROM    sys.indexes i
    WHERE   i.object_id = OBJECT_ID(N'dbo.cache')

name    allow_row_locks allow_page_locks
NULL    1   1
IND_cache_token_type    1   1

2 个答案:

答案 0 :(得分:4)

考虑一下我们有这些表:

Department (department-id (pk) , name);
Emp (EMP_ID (pk), department-id (FK), name);

从部门删除行时,为了保持完整性,RDMBS必须在Emp表中搜索并查找所有子记录。

如果department-id表中的Emp列没有索引,则Emp上将进行全表扫描,RDBMS将在操作前锁定整个Emp

如果Emp有很多记录,那么操作将需要很长时间,如果其他事务试图操纵Emp,超时或死锁可能会发生。

强烈建议在外键上创建索引以防止出现此问题。

需要更多信息来调查您的问题,我刚才提到了一个常见问题。

答案 1 :(得分:3)

1)很可能,这个DL的原因是缺失索引。尝试创建以下索引:

CREATE /*UNIQUE*/ INDEX IX_Cache_Token_Type
ON dbo.Cache (Token, Type)
INCLUDE (Value)

此索引应该有助于两种类型的查询:

select token, type, value from cache where token=@P0 and type=@P1 

delete cache where token=@P0 and type=@P1

2)如果这个索引没有消除这些DL,那么应该问问自己为什么两个并发事务试图删除/读取同一行?

3)切换到快照隔离不是一个简单的决定:

编辑#1:

DECLARE @sqlhandle1 VARBINARY(64);
SET @sqlhandle1 = 0x02000000e0a92205aebcb9dd3f38539312f56b0c41af55990000000000000000000000000000000000000000
SELECT  qp.query_plan
FROM    sys.dm_exec_query_plan(@sqlhandle1) qp

DECLARE @sqlhandle2 VARBINARY(64);
SET @sqlhandle2 = 0x0200000023b477359eec278e4060e11f3a1c194cbed41cc10000000000000000000000000000000000000000
SELECT  qp.query_plan
FROM    sys.dm_exec_query_plan(@sqlhandle2) qp

编辑#2: 我们还需要检查是否允许行/页锁:

SELECT  i.name, i.allow_row_locks, i.allow_page_locks
FROM    sys.indexes i
WHERE   i.object_id = OBJECT_ID(N'dbo.cache')