为何REPEATABLE READ隔离级别无法读取新插入行?
嘿,我来帮你捋清楚这里的问题哈!
核心问题:你没有真正实现并发执行事务
你现在把两个事务写在同一个查询脚本里,它们是按顺序串行执行的,根本没有达到“并发验证隔离级别”的目的——这就是结果和预期不符的关键原因!
要测试REPEATABLE READ隔离级别的效果,必须在两个独立的数据库会话(比如SSMS的两个查询标签页、或者两个终端窗口)分别运行对应的事务步骤,让它们真正并行起来。
正确的并发测试步骤(以SQL Server为例)
我给你拆解成清晰的步骤,你照着做就能看到REPEATABLE READ的真实效果:
1. 先初始化测试环境
随便打开一个会话(比如查询窗口1),执行以下脚本:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; CREATE TABLE testLocking(a int);
2. 启动第一个事务(会话A)
在会话A(查询窗口1)里运行:
BEGIN TRANSACTION; INSERT INTO testLocking VALUES (1); SELECT * FROM testLocking; -- 这里会返回:1 WAITFOR DELAY '000:00:30'; -- 暂停30秒,给另一个会话留操作时间 SELECT * FROM testLocking; -- 这是事务内的第二次查询 COMMIT TRANSACTION;
运行后,会话A会进入30秒的等待状态,这时候赶紧切换到第二个会话。
3. 启动第二个并发事务(会话B)
立刻打开另一个会话(查询窗口2),运行:
BEGIN TRANSACTION; INSERT INTO testLocking VALUES (2); UPDATE testLocking SET a=4 WHERE a=1; SELECT * FROM testLocking; -- 这里会话B会返回:4、2 WAITFOR DELAY '000:00:40'; COMMIT TRANSACTION;
4. 观察会话A的第二次查询结果
等会话A的30秒等待结束后,你会看到它的第二个SELECT仍然返回1——这正是REPEATABLE READ的核心特性:
- 事务启动后会建立一个一致性读快照,在事务提交前,所有查询都会基于这个快照返回数据,看不到其他事务在这段时间插入或修改的新数据(这就是“可重复读”的含义:同一个事务内多次读同一数据集,结果完全一致)
- 会话B的插入和更新操作不会被阻塞,但这些变更对会话A来说是不可见的,直到会话A自己提交事务。
关于你预期结果的误解
你预期的1、1、2、2、4其实混淆了不同会话的查询结果:
- 会话A的两次查询只会返回
1(受REPEATABLE READ隔离级别保护,看不到其他事务的变更) - 会话B自己的查询会返回
4、2(它自己的变更在当前事务内是可见的)
最后记得清理环境,任意会话执行:
DROP TABLE testLocking;
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

