SQL Server中的交易隔离水平100%可靠吗?

发布于 2025-02-13 07:25:28 字数 1309 浏览 0 评论 0原文

我正在对SQL Server中的隔离级别进行一些测试。 首先,我创建一个名为“测试”的表:

”在此处输入图像说明”

然后我在同一的2个线程中运行测试代码时间:

use test-db;
go
declare @count int = 0;
while @count<5000
begin
  set transaction isolation level read committed;
  begin transaction;

  declare @max int;
  select @max = coalesce(max(sequence_no),0) from test;
  print @max;
  insert into test (prefix, sequence_no, thread) values ('AAA', @max+1, 1);

  commit transaction;
  set @count = @count+1;
end;

第二个线程只需更改线程编号:

use test-db;
go
declare @count int = 0;
while @count<5000
begin
  set transaction isolation level read committed;
  begin transaction;

  declare @max int;
  select @max = coalesce(max(sequence_no),0) from test;
  print @max;
  insert into test (prefix, sequence_no, thread) values ('AAA', @max+1, 2);


  commit transaction;
  set @count = @count+1;
end;

在读取订单模式下,当另一个线程不提交时,代码应等待读取最大序列数,这意味着它们不会生成相同的sequence_no。 但这通常给我一个错误:

违反主密钥约束“ pk_test”。无法在对象“ dbo.test-db”中插入重复键。重复的键值为(AAA,2402)。

我再次以可重复的读取模式进行测试,并且相同。

有人可以解释为什么交易之间的阅读查询会崩溃吗?
这是否意味着隔离水平不是100%可靠的?

I'm doing some test about the isolation level in SQL Server.
First I create a table called test with this structure:

enter image description here

Then I run the test code with 2 threads at the same time:

use test-db;
go
declare @count int = 0;
while @count<5000
begin
  set transaction isolation level read committed;
  begin transaction;

  declare @max int;
  select @max = coalesce(max(sequence_no),0) from test;
  print @max;
  insert into test (prefix, sequence_no, thread) values ('AAA', @max+1, 1);

  commit transaction;
  set @count = @count+1;
end;

The second thread just change the thread number:

use test-db;
go
declare @count int = 0;
while @count<5000
begin
  set transaction isolation level read committed;
  begin transaction;

  declare @max int;
  select @max = coalesce(max(sequence_no),0) from test;
  print @max;
  insert into test (prefix, sequence_no, thread) values ('AAA', @max+1, 2);


  commit transaction;
  set @count = @count+1;
end;

Under read committed mode, the code should wait for read the max number of sequence when the other thread is not commit, which means they won't generate a same sequence_no.
But it often give me a error:

Violation of PRIMARY KEY constraint 'PK_test'. Cannot insert duplicate key in object 'dbo.test-db'. The duplicate key value is (AAA, 2402).

I test it in repeatable read mode again, and it's the same.

Can someone explain why the reading query between transaction will get crash?
Does it means that isolation level isn't 100% reliable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半世蒼涼 2025-02-20 07:25:28

您需要使用可序列化的隔离,并且还需要一个updlock来避免僵局:

SELECT @max = coalesce(max(sequence_no),0)
FROM dbo.test WITH (UPDLOCK, SERIALIZABLE);

这对于并发很糟糕,因此您应该真正使用身份或序列。

You need to use SERIALIZABLE isolation and an UPDLOCK is also required to avoid deadlocks:

SELECT @max = coalesce(max(sequence_no),0)
FROM dbo.test WITH (UPDLOCK, SERIALIZABLE);

This is awful for concurrency so you should really use an identity or a sequence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文