kub*_*003 6 sql sql-server transaction-isolation
我有以下代码:
set transaction isolation level read committed; --this is for clarity only
DECLARE @jobName nvarchar(128);
BEGIN TRAN
SELECT @jobName = JobName
FROM dbo.JobDetails
WHERE ExecutionState_Status = 1
WAITFOR DELAY '00:00:10'
UPDATE dbo.JobDetails
SET ExecutionState_Status = 10
WHERE JobName = @jobName
COMMIT
Run Code Online (Sandbox Code Playgroud)
第二件几乎是相同的:
set transaction isolation level read committed;
DECLARE @jobName nvarchar(128);
BEGIN TRAN
SELECT @jobName = JobName
FROM dbo.JobDetails
WHERE ExecutionState_Status = 1
WAITFOR DELAY '00:00:15'
UPDATE dbo.JobDetails
SET ExecutionState_Status = 20
WHERE JobName = @jobName
COMMIT
Run Code Online (Sandbox Code Playgroud)
不同之处在于我们设定的状态(10对20)和延迟(10对15对).
我在Management Studio中并行执行它们 - 两个选项卡.现在问题 - 读取已提交事务隔离级别按预期工作 - 应用最后一次修改并且两个脚本都成功执行.
然而,这不是我想要的 - 我只想执行一个而第二个应该什么都不做.这就是我尝试将级别更改为REPEATABLE READ的原因.根据我的知识(我现在想要挑战),它应该像这样:
不幸的是,我看到的结果远非如此 - 事务处于死锁状态,其中一个被SQL Server杀死.我真的不明白为什么会这样,因为他们以相同的顺序访问资源.
以下是测试所需的脚本:
CREATE TABLE [dbo].[JobDetails](
[JobName] [nvarchar](128) NOT NULL,
[ExecutionState_Status] [int] NULL DEFAULT ((0)),
CONSTRAINT [PK_dbo.JobDetails] PRIMARY KEY CLUSTERED
(
[JobName] ASC
))
GO
INSERT INTO JobDetails VALUES( 'My Job', 1)
UPDATE JobDetails SET ExecutionState_Status = 1
Run Code Online (Sandbox Code Playgroud)
补充说明:
WHERE根据PK 发送更新.我知道我可以在没有ORM更新的情况下编写该代码WHERE ExecutionState_Status = 1这个假设是错误的:
第二个事务同时启动,并且无法执行选择,因为它被第一个事务锁定
两个repeatable read事务都select获取并保持S对密钥的锁定,直到commit。 S锁是兼容的。update当尝试获取X与锁不兼容的锁时,它们会陷入死锁S。与此相反,select在read commited事务中立即释放S锁。
使用 exec sp_lock 来查看锁,例如
DECLARE @jobName nvarchar(128);
BEGIN TRAN
SELECT @jobName = JobName
FROM dbo.JobDetails
WHERE ExecutionState_Status = 1
WAITFOR DELAY '00:00:10'
exec sp_lock 58,57
UPDATE dbo.JobDetails
SET ExecutionState_Status = 10
WHERE JobName = @jobName
COMMIT
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
583 次 |
| 最近记录: |