为啥SQLServer到处都要加nolock

本文通过实验对比了MySQL与SQLServer在处理未提交数据时的不同行为。在SQLServer中,使用WITH(NOLOCK)可以读取未提交的数据,而在MySQL中,默认情况下就可以读取未提交前的数据状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查看公司.net项目,很多逻辑都是在存储过程中实现,发现查询都添加了WITH (NOLOCK),我这边java转过来的小白,看起真是一脸懵逼。

 

先在MySQL里写了一个查询语句,比样子加了nolock,提示语法不正确,难道是用READUNCOMMITTED?  依然提示语法不正确,

看来MySQL是不支持nolock之类的语法

然后的问题变成了,为什么MySQL不需要支持nolock之类的语法,或者如果MySQL不支持nolock,修改记录导致锁表怎么办?

所以我做了下面的实验

给开了两个MySQL连接,(顺便插一句,因为用的客户端是SQLyog,本以为跟SQL Server Management Studio一样每个“询问”就是一个连接,其实不是,每个连接都要“创建新连接”,我自己测试半天才发现这个问题)

 第一个MySQL连接执行查询

START TRANSACTION;
UPDATE testtable SET NAME='newvalue' WHERE id=1

因为事务没有提交,如果是SQLServer的默认情况下,第二个连接再查询同一条记录,肯定会被阻塞的。如果SQLServer查询加了Nolock读取到的是还未commit的脏值“newvalue”

第二个MySQL连接我执行查询

SELECT * FROM `testtable`

我发现既没有发生阻塞,也没有发生脏读,查询到的是老的值,并没有读到未提交的新值newvalue

也就是说MySQL和SQLServer默认维护事务的机制是不同的,

SQLServer 默认情况下一个事务修改了某个值,在这个事务提交前,是阻塞其他连接来读取这个修改中的值的,如果加nolock读取到的是修改后为提交的值(也就是脏读,因为可能这个值最终会回滚)

MySQL 默认情况下,一个事务修改了某个值,在这个事务提交前,不阻塞其他连接来读取这个修改中的值,并且读取到的是修改前的值。

对于互联网公司,绝大多数场景,都不希望写的事务来阻塞读,

所以SQLServer建议加nolock

MySQL本身就不阻塞,nolock也就没有意义了。。.

在 SQL Server 中,`NOLOCK` 是一种查询提示(Table Hint),用于指示查询优化器在读取表时不需要获取共享锁或互斥锁,从而避免阻塞其他操作。这种行为允许查询在读取数据时不会因为其他事务未提交而被阻塞,同时也可以减少锁资源的占用,提升查询性能。然而,这种操作也可能导致读取到未提交的“脏”数据[^2]。 ### 使用方法 `NOLOCK` 查询提示通常以 `WITH(NOLOCK)` 的形式附在表名之后,适用于 `SELECT` 语句。其基本语法如下: ```sql SELECT column1, column2 FROM table_name WITH(NOLOCK) WHERE condition; ``` 例如,假设有一个名为 `Employees` 的表,可以使用以下语句查询数据而不会受到锁的影响: ```sql SELECT Name, Department FROM Employees WITH(NOLOCK) WHERE Salary > 50000; ``` ### 注意事项 1. **脏读风险** 使用 `NOLOCK` 时,可能会读取到其他事务尚未提交的数据。如果这些数据随后被回滚,那么查询结果中将包含不存在的数据,这可能导致业务逻辑错误。 2. **数据一致性问题** 由于 `NOLOCK` 绕过了锁机制,因此可能会导致查询结果中出现重复记录或遗漏记录的情况,尤其是在数据频繁更新的环境中。 3. **适用场景** `NOLOCK` 适用于对数据一致性要求不高的场景,例如报表生成、数据分析等,而不建议在需要高精度和一致性的事务处理中使用。 4. **性能影响** 虽然 `NOLOCK` 可以减少锁争用并提高查询性能,但在某些情况下,它可能导致查询计划的变化,从而影响性能。 5. **索引使用** 如果表具有非聚集索引,并且希望在使用 `NOLOCK` 时指定索引,可以使用 `WITH(NOLOCK, INDEX(index_name))` 的形式[^1]。 6. **与事务隔离级别的关系** `NOLOCK` 实际上等同于 `READ UNCOMMITTED` 隔离级别。因此,在使用 `NOLOCK` 时,应确保理解当前数据库的事务隔离级别及其对查询行为的影响。 ### 示例:结合索引提示使用 NOLOCK ```sql SELECT Name, Department FROM Employees WITH(NOLOCK, INDEX(IX_Employees_Department)) WHERE Department = 'HR'; ``` 上述语句将强制查询使用名为 `IX_Employees_Department` 的索引,并且不会阻塞其他事务。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值