读/写死锁

我喜欢写死锁这个话题,由于在你写代码的时候,若是不考虑仔细,会有太多不一样的方法和状况形成死锁。在今天的文章里,我想向你展现下,从同个表,用不一样的顺序来读写记录时,会发生死锁的状况。sql

读/写死锁

下列代码展现了简单的表定义,这里我也插入2条记录。 spa

-- Create a new table
CREATE TABLE Foo
(
    Col1 INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
    Col2 INT,
    Col3 INT
)
GO

-- Insert 2 records
INSERT INTO Foo VALUES (1, 1), (2, 2)
GO

SELECT * FROM Foo
GO

如今假设下列状况:你有2个查询,用来读写访问记录,但你用不一样的顺序访问记录。第1个事务进行下列操做code

  • UPDATE第1条记录
  • SELECT第2条记录

第2个事务用相反的顺序访问一样的记录:blog

  • UPDATE第2条记录
  • SELECT第1条记录

下列代码展现了这2个事务:事务

-- UPDATE 1st record
-- SELECT 2nd record
BEGIN TRANSACTION

UPDATE Foo SET Col3 = 3
WHERE Col1 = 1

SELECT * FROM Foo
WHERE Col1 = 2

ROLLBACK
GO

-- UPDATE 2nd record
-- SELECT 1st record
BEGIN TRANSACTION

UPDATE Foo SET Col3 = 3
WHERE Col1 = 2

SELECT * FROM Foo
WHERE Col1 = 1

ROLLBACK
GO

若是时机合适的话,这里很容易触发死锁。由于2个事务都要在第1条和第2条记录上得到排它锁(X),而后他们不能在另外一条记录上得到共享锁(S)——死锁发生!get

你如何解决这个死锁呢?有不少方法:it

  • 在你整个事务里按一样的顺序访问记录(第1条,而后第2条)
  • 在事务外进行SELECT语句
  • 在SELECT语句期间,启用提交读快照隔离级别( Read Committed Snapshot Isolation )来避免共享锁

小结

在今天的文章里,我向你展现了,SQL Server里,当你在一个表,在不一样的顺序访问的事务里,是很容易触发死锁的。当你写你的查询时,你必需要认真考虑,按实际状况实现你的查询。常常有其余人能够阻塞你。io

原文连接:

https://www.sqlpassion.at/archive/2016/12/19/writeread-deadlocks table

相关文章
相关标签/搜索