记一次SQL事务隔离级别的问题

文章描述了一个在多服务并发写入数据库场景下,由于事务隔离级别设置不当可能导致的数据遗漏问题。第一个服务插入数据但未提交,第二个服务随后提交插入,第三个服务在READUNCOMMITTED级别下查询,可能会漏掉未提交的数据。而在READCOMMITTED或更高隔离级别下,可以避免此类问题,但可能产生阻塞。正确的事务管理和隔离级别选择对确保数据一致性至关重要。
摘要由CSDN通过智能技术生成

两个服务往同一个库里写数据,第一个服务先插入了id为1的数据但没有提交事务,第二个服务后插入id为2的数据并且提交了事务,这时候第三个服务去查询,查到了第二个服务id为2的数据。这时候根据第三个服务的业务逻辑,认为id<=2的数据都已经处理完了,下次就从id>2开始处理了,这样就漏掉了id为1的数据!

使用sql脚本复现了这种情况,下面提供测试脚本:

--建测试表
CREATE TABLE transactions(
	[id] [int] IDENTITY(1,1) NOT NULL,
	[insert_datetime] [datetime] NOT NULL
 CONSTRAINT [pk_transactions] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)) ON [PRIMARY]
GO
--模拟第一个服务的插入
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
Begin Transaction

Insert into transactions(insert_datetime) values(GETDATE())

--Commit Transaction
--模拟第二个服务的插入
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
Begin Transaction

Insert into transactions(insert_datetime) values(GETDATE())

Commit Transaction 
--第三个服务,负责查询
--READ UNCOMMITTED非常不安全,这里仅作参照
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM transactions
GO
--READ COMMITTED是一般的数据访问层的默认隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT * FROM transactions
GO
--REPEATABLE READ提高的这个级别以上就能避免这个问题
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
SELECT * FROM transactions
GO

测试流程:

数据库工具为三个服务开启三个独立的窗口,这样它们就运行在不同的事务里。先执行第一个服务的插入,此时第一个服务没有Commit,再执行第二个服务的插入,第二个服务先Commit了。这个时候第三个服务来查询得到结果如图:

 可以看到第一句查询把未提交的数据也查出来了,第二句是安全又效率的,但根据应用层的业务逻辑就把id为1的数据跳过了。第三句会一直等待第一个服务解锁(显示“正在执行查询…”)。当我们把第一个服务Commit,第三个服务的第三句查询也就能查出来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值