使用Sqlserver更新锁防止数据脏读
有时候我们需要控制某条记录在程序读取后就不再进行更新,直到事务执行完释放后才可以。这时候我们就可以将所有要操作当前记录的查询加上更新锁,以防止查询后被其它事务修改。这种操作只锁定表中某行而不会锁定整个表,体验更好。
测试sql代码如下:
在一个查询中执行如下语句
begin tran SELECT InvestState FROM InvestOrdersABC WITH (UPDLOCK) where id=10005 waitfor delay '00:00:10' update InvestOrdersABC set InvestState='2' where id=10005 commit tran
1、在另外的一个查询中执行以下语句
SELECT InvestState FROM InvestOrdersABC where id=10005
发现在第一个事务执行完以前查到的数值还是原来的数值0,直到更新完成后才会变成2,如果加上锁,代码如下:
SELECT InvestState FROM InvestOrdersABC WITH (UPDLOCK) where id=10005
发现sql语句必须等到第一个连接里的事务完成才执行完成,这是因为这个sql的连接的更新锁认为第一个事务里的更新锁可能会对数据进行修改,因此必须等事务执行完成才执行。此时更新锁变为排他锁。
2、如果执行更新操作:
begin tran update InvestOrders set InvestState='3' where id=10005 commit tran
发现无法更改,只能等到第一个查询完成后才会进行修改。其实和加锁不加锁已经没什么关系,为什么呢?因为SQL Server在执行INSERT、 UPDATE 或DELETE 命令时,会自动使用独占锁。
3、上文的事务未加隔离级别,事务的默认隔离级别为READ committed,不加锁因此在第1点里还可以进行查询。当数据库事务的隔离级别为REPEATABLE READ,SERIALIZABLE时,如果查询需要加共享锁:
SELECT InvestState FROM InvestOrdersABC WITH (HoldLOCK) where id=10005