我的MS SQL Server 2008数据库中有2个表:
[Person]
-Id
-Name
-Car_Id
和
[Car]
-Id
-Mileage
现在我运行的服务器进程不断更新不同车辆的里程。
UPDATE Car SET Mileage=1234 WHERE Id=7
然后我有一个客户网格,显示他们的汽车的人和里程。这也会定期更新:
SELECT p.Name, c.Mileage
FROM Person AS p
INNER JOIN Car AS c on p.Car_Id = c.Id
然后SQL服务器中止SELECT查询。据我所知,这与主键上的某种范围锁定有关。一个由UPDATE WHERE子句引起,另一个由INNER JOIN条件引起。
这个假设是否正确?
这种密钥锁定死锁问题的首选解决方案是什么?我假设唯一的方法是重试SELECT或更改事务隔离级别。我不只是想在不完全理解这里的问题的情况下降低隔离级别。
修改
表格的更多细节:
CREATE TABLE [dbo].[Car](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Mileage] [int] NULL,
CONSTRAINT [PK_dbo.Car] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Car_Id] [int] NULL,
CONSTRAINT [PK_dbo.Person] PRIMARY KEY CLUSTERED
ALTER TABLE [dbo].[Person] WITH CHECK ADD CONSTRAINT [FK_dbo.Person_dbo.Car_Car_Id] FOREIGN KEY([Car_Id])
REFERENCES [dbo].[Car] ([Id])
ALTER TABLE [dbo].[Person] CHECK CONSTRAINT [FK_dbo.Person_dbo.Car_Car_Id]
CREATE NONCLUSTERED INDEX [IX_Car_Id] ON [dbo].[Person]
(
[Car_Id] ASC
)
修改2
刚刚发生的一件事在这里也很重要: 服务器端的事务中总有几个UPDATE,因此并非每个UPDATE都在一个事务中。基本上所有改变的汽车都在一次交易中更新。
答案 0 :(得分:1)
事实证明,在事务中只运行一个UPDATE可以解决问题。谢谢大家的意见。
答案 1 :(得分:0)
首先,如果更改更新以使其在值已经正确的情况下不更新任何行,是否有帮助?
UPDATE Car SET Mileage=1234 WHERE Id=7 AND Mileage <> 1234;
我认为我不能直接回答你的问题,但试试这个链接Is it possible to force row level locking in SQL Server?。
UPDATE Car WITH (ROWLOCK) SET Mileage=1234 WHERE Id=7 AND Mileage <> 1234;
答案 2 :(得分:0)
每当您更新表时,您都会获得对已更新/删除的表行的独占(写入)锁定。 当获得排他锁时,不能获得共享锁(SELECTs所需)。对此最简单的解决方案是回滚事务并让另一个完成并再试一次。我也不会建议你降低隔离度。序列化应该工作正常。 你更新后立即提交?即时提交;更新后的声明可能是您的问题的解决方案,因为在提交后您“回馈”您的独占锁。