为何SELECT查询被INSERT阻塞?读写不阻塞的认知困惑求助
为什么你的SQL Server读写操作会互相阻塞?
嗨,这个问题其实挺典型的,咱们来拆解一下你遇到的情况:
你的认知偏差在哪里?
你之前认为“写入操作不会阻塞读取操作(反之亦然)”,这个假设不完全正确——SQL Server的锁机制和事务隔离级别共同决定了读写是否会互相阻塞,默认场景下并不是完全无阻塞的。
你的场景里阻塞发生的原因
咱们一步步看你的操作:
- 你开启了
IMPLICIT_TRANSACTIONS,这意味着执行INSERT后事务不会自动提交,锁会一直被持有,直到你显式执行COMMIT或ROLLBACK。 - 当你执行
INSERT时,SQL Server会对插入的行加上排他锁(X锁),这种锁会阻止其他事务对该行进行读取或写入操作(在默认隔离级别下)。 - 默认情况下,SQL Server的事务隔离级别是
READ COMMITTED,这个级别要求SELECT语句必须读取已提交的数据,所以它会等待行上的排他锁释放后才能继续执行——哪怕你换了sa账户,锁的规则是全局生效的,所以还是会被阻塞。
解决方法
针对你的场景,有几个可行的解决方向:
1. 及时提交/回滚未完成的事务
这是最直接的方法,在执行完INSERT后,立即执行:
COMMIT; -- 或者 ROLLBACK; 如果不需要保留插入的数据
释放锁之后,SELECT语句就能立即返回结果了。
2. 修改事务隔离级别
如果你需要在不提交写事务的情况下读取数据,可以调整隔离级别:
- 允许脏读(READ UNCOMMITTED):这个级别会跳过锁检查,直接读取未提交的数据,适合对数据一致性要求不高的场景:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM [dbo].[MyTab]; - 使用快照隔离(SNAPSHOT ISOLATION):这个级别会通过行版本存储,读取事务开始时的数据快照,完全不会被写操作阻塞,同时也能避免脏读:
首先开启数据库的快照隔离支持:
然后在查询会话中设置隔离级别:ALTER DATABASE [testdb] SET ALLOW_SNAPSHOT_ISOLATION ON;SET TRANSACTION ISOLATION LEVEL SNAPSHOT; SELECT * FROM [dbo].[MyTab];
3. 避免依赖隐式事务
IMPLICIT_TRANSACTIONS很容易导致事务长时间未提交,除非你有明确的业务需求,否则建议关闭它,改用显式的BEGIN TRANSACTION、COMMIT来管理事务,这样能更清晰地控制锁的生命周期。
内容的提问来源于stack exchange,提问作者RGO
相关产品推荐
相关产品推荐

