1:脏读,一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用户放弃修改,数据回到修改之前,这两个不同的结果就是脏读。
2:不可重复读,一个用户的一个操作是一个事务,这个事务分两次读取同一条记录,如果第一次读取后,有另外用户修改了这个数据,然后第二次读取的数据正好是其它用户修改的数据,这样造成两次读取的记录不同,如果事务中锁定这条记录就可以避免。
3:幻读,指用户读取一批记录的情况,用户两次查询同一条件的一批记录,第一次查询后,有其它用户对这批数据做了修改,方法可能是修改,删除,新增,第二次查询时,会发现第一次查询的记录条目有的不在第二次查询结果中,或者是第二次查询的条目不在第一次查询的内容中。
为了避免并发访问产生的不利影响,SQL Server有两种并发访问的控制机制:锁、行版本控制,表后面加nolock是解决并发访问的方案之一。
(一) 锁的介绍
每个事务对所依赖的资源会请求不同类型的锁,它可以阻止其他事务以某种可能会导致事务请求锁出错的方式修改资源。当事务不再依赖锁定的资源时,锁将被释放。
锁的类型:
1:表类型:锁定整个表;
2:行类型:锁定某个行;
3:文件类型:锁定某个数据库文件;
4:数据库类型:锁定整个数据库;
5:页类型:锁定8K为单位的数据库页。
锁的分类还有一种分法,就是按用户和数据库对象来分:1). 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁
1:共享 (S) :用于不更改或不更新数据的操作(只读操作),一般常见的例如select语句。
2:更新 (U) :用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。
3:排它 (X) :用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。
2). 从程序员的角度看:分为乐观锁和悲观锁。
1:乐观锁:完全依靠数据库来管理锁的工作。
2:悲观锁:程序员自己管理数据或对象上的锁处理。
SQLServer通过设置事务的隔离级别自动管理锁的设置和控制。锁管理器通过查询分析器分析待执行的sql语句,来判断语句将会访问哪些资源,进行什么操作,然后结合设定的隔离级别自动分配管理需要用到的锁。
(二)行版本控制
当启用了基于行版本控制的隔离级别时,数据库引擎 将维护修改的每一行的版本。应用程序可以指定事务使用行版本查看事务或查询开始时存在的数据,而不是使用锁保护所有读取。通过使用行版本控制,读取操作阻止其他事务的可能性将大大降低。也就是相当于针对所有的表在查询时都会加上nolock,同样会产生脏读的现象,但差别在于在一个统一管理的地方。说到了基于行版本控制的隔离级别,那什么是隔离级别
隔离级别的用处:控制锁的应用,即什么场景应用什么样的锁机制。最终目的:解决并发处理带来的种种问题。
隔离级别的分类:
Read Uncommitted:读未提交数据(这个通常很少用)使用这种隔离级别并不是说在读取或者更新数据的时候不加锁。其实还是加锁的,只是在执行完操作之后马上释放锁。而不是等到事务结束之后再释放。对于共享锁,排他锁都是这样。Read Committed:读已提交数据(这个很常用,也常是数据库默认的设置)这种隔离级别共享锁在读取数据之后马上释放。。而排他锁则是在事务结束的时候再释放。
Repeatable Read:可重复读这种隔离级别共享锁和排他锁都是在事务结束的时候再释放的。因此叫“可重复读”,即一个事务所读取的数据是不会被别的事务更新的。。。在事务执行过程中任何时候都可以读取刚才读过的数据。读过的数据是不会被改变的,直到事务结束。
Serializable:串行化