SQL Server DBA面试知识点(一)--SQL Server的事务隔离级别详解
阅读原文时间:2021年04月20日阅读:1

首先什么是事务

事务指数据操作的最小逻辑单元。一个事务要么完成,要么不完成,不存在粒度更小的数据操作。
在关系型数据中,当没有使用“begin transaction”显式的定义一个事务时,一条SQL语句默认就是一个transaction。例如:

insert into my_table_1
select *
from my_table_2

这条语句就是一个transaction。my_table_2中的所有数据都会被插入到my_table_1中,要么操作失败一条都没有插入,要么全部插入,不存在其他可能性。
需要注意的是SQL Server是隐式提交事务的,即运行一条DML会直接提交到数据库,不需要显式指定Commit关键字。但Oracle则不会自动提交DML,除非遇到一条Commit或Rollback语句。在上例中,如果插入了一半后发生了某种错误,Oracle将回滚已插入的那部分数据,这称为statement-level rollback,且回滚后事务挂起,等待用户的进一步指令。
在SQL Server中,一个存储过程或函数中包含多个SQL语句,且没有显式指定事务时,多条SQL语句默认不在一个transaction里。即可能出现一个存储过程中的前半部分SQL执行成功,但后面的SQL没有执行的情况。
如果显式的使用“begin transaction”定义了transaction,则被包含到语句里的多条SQL属于一个transaction。
另外在SQL Server中,使用Savepoint可以有条件的回滚部分事务。虽然这样做破坏了事务的基本含义,但由于通常回滚操作的代价很高,因此部分回滚事务是一种现实的折中选择。Oracle也有类似的功能。

ACID原则

ACID(Atomicity, Consistency, Isolation, Durability)是关系型数据库都采用的原则。具体含义是:
Atomicity原子性:指一个事务(transaction)要么全部执行,要么完全不执行。也就是不允许一个事物只执行了一半就停止。
consistency一致性: any transaction will bring the database from one valid state to another.在分布式系统中,一致性也分很多种或者说程度,即一个事务对分布式系统的影响可能是局部的。但在关系型数据库中,一致性就是指强一致性,即整个系统处于统一的状态。
Durability持久性:当事务运行成功后,对系统状态的影响是持久的,不会无缘无故的撤销。在实现上,持久性一般对应着数据在硬盘上的持久化。
Isolation独立性:当有多个事务同时运行时,它们之间互相独立,互不干扰的程度。我们今天要说的事务隔离级别就是关于Isolation。

事务隔离级别

事务隔离级别在关系型数据库中就是指isolation的程度。而事务之间的独立性是靠锁来实现的。因此,数据库工作在不同的事务隔离级别下就意味着数据库应用不同的锁策略。
标准SQL定义了4种级别,由低到高为:

  1. READ UNCOMMITTED
    一个事务没commit的更改也可以被另外一个事务读取到。即允许所谓的dirty reads,脏读。
    In this isolation level, do not issue shared locks to prevent other transactions from modifying data read by the current transaction. READ UNCOMMITTED transactions are also not blocked by exclusive locks that would prevent the current transaction from reading rows that have been modified but not committed by other transactions.

  2. READ COMMITTED
    SQL Server和Oracle的默认隔离级别. 这种隔离级别会出现nonRepeatable Read和Phantom read。
    会发生不可重复读的原因是,这种级别要求当前事务不能去读取那些已经被别的事务修改,但还未提交的数据。这样就避免了脏读。
    但在如下情况会发生重复读:

    事务A
    begin transaction
    select * from tableA
    –此时事务B修改了tableA中的数据并提交。
    select * from tableA
    –第二次查询会返回被事务B修改的数据。因此在当前事务中的两次查询返回了不同的结果,也就是说事务A受到了事务B的影响,称为不可重复读。
    commit

  3. REPEATABLE READ
    这种隔离级别保证当前事务正在读的数据不允许被其他事务修改。这种隔离级别在如下情况会发生phantom read幻象读:

    事务A
    begin transaction
    select * from tableA
    –此时事务B向tableA中插入了新数据并提交。因为新数据不是当前事务正在读的数据,因此允许被插入。
    select * from tableA
    –第二次查询会返回被事务B新插入的数据。因此在当前事务中的第两次查询返回了更多的数据,因此事务A仍然受到了事务B的影响,称为幻象读。
    commit

  4. SERIALIZABLE
    即所有事务只能串行执行。只有在这种隔离级别下,事务之间才会完全无干扰,但并发性最低。

sqlserver共有5种,相对标准SQL的定义,多了一个SNAPSHOT。而oracle也定义了5个,多了一个read only。
SNAPSHOT介于REPEATABLE READ和SERIALIZABLE之间。SNAPSHOT是一个很特殊的隔离级别,它不仅仅是使用了不同的锁策略,而且维护对一份数据的多份不同数据版本,不同的操作针对不同的数据版本进行,因此来增加并发度并保证数据修改的一致性。SQL Server会在事务开始时将涉及的数据copy到tempdb并在其中维护多个数据版本。
SNAPSHOT相对比较复杂,有兴趣的读者自行参考:
https://msdn.microsoft.com/en-us/library/tcbchxcb(v=vs.110).aspx

另外,事务隔离级别是数据库级别的参数,也就是说不同的数据库可以选择不同的隔离级别。但在一个事务中,可以使用SET来指定隔离级别,此时的设置仅影响该事务的隔离级别。