SQL Server 事务隔离级别

数据库事务并发带来的问题有:更新丢失、脏读、不可重复读、幻象读。假设张三办了一张招商银行卡,余额100元,分别说明上述情况。

1、更新丢失:一个事务的更新覆盖了另一个事务的更新。事务A:向银行卡存钱100元。事务B:向银行卡存钱200元。A和B同时读到银行卡的余额,分别更新余额,后提交的事务B覆盖了事务A的更新。更新丢失本质上是写操作的冲突,解决办法是一个一个地写。

2、脏读:一个事务读取了另一个事务未提交的数据。事务A:张三妻子给张三转账100元。事务B:张三查询余额。事务A转账后(还未提交),事务B查询多了100元。事务A由于某种问题,比如超时,进行回滚。事务B查询到的数据是假数据。脏读本质上是读写操作的冲突,解决办法是写完之后再读。

3、不可重复读:一个事务两次读取同一个数据,两次读取的数据不一致。事务A:张三妻子给张三转账100元。事务B:张三两次查询余额。事务B第一次查询余额,事务A还没有转账,第二次查询余额,事务A已经转账了,导致一个事务中,两次读取同一个数据,读取的数据不一致。不可重复读本质上是读写操作的冲突,解决办法是读完再写。

4、幻象读:一个事务两次读取一个范围的记录,两次读取的记录数不一致。事务A:张三妻子两次查询张三有几张银行卡。事务B:张三新办一张银行卡。事务A第一次查询银行卡数的时候,张三还没有新办银行卡,第二次查询银行卡数的时候,张三已经新办了一张银行卡,导致两次读取的银行卡数不一样。幻象读本质上是读写操作的冲突,解决办法是读完再写。

Read Uncommitted (未提交读)

隔离级别最低,容易产生的问题就是脏读,因为可以读取其它事务修改了的但是没有提交的数据。它的作用跟在事务中 SELECT 语句对象表上设置 (NOLOCK) 相同。

Read Committed (已提交读)

这是 SQL Server 的默认设置,已提交读,可以避免脏读,可以满足大多数要求。

事务中的语句不能读取已由其它事务做出修改但是还未提交的数据,但是能够读取由其它事务做出修改并提交了的数据。

也就是说,有可能会出现 Non-Repeatable Reads 不可重复读取和 Phantom Reads 幻读的情况,因为当前事务中可能出现两次读取同一资源,但是两次读取的过程之间,另外一事务可能对这一资源完成了读取更新并提交的行为,这样数据前后可能就不一致了。因此,这一个默认的隔离级别能够解决脏读但是解决不了 Non-Repeatable Reads 不可重复读。

Repeatable Read (可重复读)

不能读取已由其它事务修改了但是未提交的行,其它任何事务也不能修改在当前事务完成之前由当前事务读取的数据。

但是对于其它事务插入的新行数据,当前事务第二次访问表行时会检索这一新行。

因此,这一个隔离级别的设置解决了 Non-Repeatable Reads 不可重复读取的问题,但是避免不了 Phantom Reads 幻读。

SNAPSHOT (快照隔离)

可以解决幻读 Phantom Reads 的问题,当前事务中读取的数据在整个事务开始到事务提交结束之间,这个数据版本是一致的。

其它的事务可能对这些数据做出修改,但是对于当前事务来说它是看不到这些变化。

有点类似于当前事务拿到这个数据的时候是拿到这个数据的快照,因此在这个快照上做出的操作同一事务中前后几次操作都是基于同一数据版本。

因此,这一个隔离级别的设置可以解决 Phantom Reads 幻读问题。

但是要注意的是,其它事务是可以在当前事务完成之前修改由当前事务读取的数据。

在使用 SNAPSHOT 之前要注意,默认情况下数据库不允许设置 SNAPSHOT 隔离级别,直接设置会出现类似于这样的错误:

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Msg 3952, Level 16, State 1, Line 8

Snapshot isolation transaction failed accessing database 'BIWORK_SSIS' because snapshot isolation is not allowed in this database. Use ALTER DATABASE to allow snapshot isolation.

所以要使用 SET 命令开启这个支持

ALTER DATABASE BIWORK_SSIS
SET ALLOW_SNAPSHOT_ISOLATION ON

SERIALIZABLE(序列化)

性能最低,隔离级别最高最严格,可以几乎上面提到的所有问题。比如

不能读取其它已由其它事务修改但是没有提交的数据,

不允许其它事务在当前事务完成修改之前修改由当前事务读取的数据,

不允许其它事务在当前事务完成修改之前插入新的行。

它的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同,并发级别比较低但又对安全性要求比较高的时候可以考虑使用。

如果并发级别很高,使用这个隔离级别,性能瓶颈将非常严重。

http://www.cnblogs.com/biwork/p/3338844.html

http://www.cnblogs.com/lxconan/archive/2011/10/20/2218396.html

https://segmentfault.com/a/1190000004469395#articleHeader11

原文地址:https://www.cnblogs.com/hongdada/p/3392711.html