(3.12)常用知识-事务的隔离级别

首先什么是事务
  事务指数据操作的最小逻辑单元。一个事务要么完成,要么不完成,不存在粒度更小的数据操作。
在关系型数据中,当没有使用“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。


1、脏读:一个事务读到另外一个事务还没有提交的数据。
解决方法:把事务隔离级别调整到READ COMMITTED,即SET TRAN ISOLATION LEVEL READ COMMITTED。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果,因为此时事务以已经把自己的更改ROLLBACK了,所以事务二可以返回正确的结果。
  

  


2、更新丢失:

  

扫描二维码关注公众号,回复: 1499040 查看本文章


3、 不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同。
解决方法:把事务隔离级别调整到REPEATABLE READ。使用SET TRAN ISOLATION LEVEL REPEATABLE READ。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。

  



4、幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同。
解决方法:把事务隔离级别调整到SERIALIZABLE。使用SET TRAN ISOLATION LEVEL SERIALIZABLE。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。

   

  

总结:
1.READ UNCOMMITTED
概述:不作任何锁
READ UNCOMMITTED:未提交读,读脏数据
默认的读操作:需要请求共享锁,允许其他事物读锁定的数据但不允许修改.
READ UNCOMMITTED:读操作不申请锁,运行读取未提交的修改,也就是允许读脏数据,读操作不会影响写操作请求排他锁.

2.READ COMMITTED
概述:读的时候加共享锁(读完就释放,不会在一个事务过程中保持共享锁)
   可以避免脏读,但会出现不可重复读、幻读问题(锁定正在读取的行)。
READ COMMITTED(已提交读)是SQL SERVER默认的隔离级别,可以避免读取未提交的数据,隔离级别比READ UNCOMMITTED未提交读的级别更高;
该隔离级别读操作之前首先申请并获得共享锁,允许其他读操作读取该锁定的数据,但是写操作必须等待锁释放,一般读操作读取完就会立刻释放共享锁。

注意:但是由于READ COMMITTED读操作一完成就立即释放共享锁,读操作不会在一个事务过程中保持共享锁,也就是说在一个事务的的两个查询过程之间有另一个回话对数据资源进行了更改,会导致一个事务的两次查询得到的结果不一致,这种现象称之为不可重复读.

3.REPEATABLE READ(可重复读):
概述:读的时候加共享锁(一个事务过程中保持共享锁),避免不可重复读,实现可重复读。
保证在一个事务中的两个读操作之间,其他的事务不能修改当前事务读取的数据,该级别事务获取数据前必须先获得共享锁同时获得的共享锁不立即释放一直保持共享锁至事务完成,所以此隔离级别查询完并提交事务很重要。

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

测试:
1.RC模式
场景1 问:2中得到的数据是update之前的还是update之后的?
1 update
2 select
1 rollback
session 1:
1 begin tran a
2 select * from test104
3 waitfor delay '00:00:10'
4 update test104 set name = 'b' where name = 'a'
5 waitfor delay '00:00:10'
6 select * from test104
7 rollback tran a
session 2:
select * from test104
结论:RC模式到底是如何避免脏读的呢,我一直不太明白,后面我终于明白了,这里用实例实测说明;
【1】session 1执行1-3行数据时,session2也可以执行查询,并且两个会话结果相同
【2】当session 1 执行 4行后,只要事务没有执行到提交或者回滚, session 2 无法进行查询,这应该是加了排它锁的原因。

猜你喜欢

转载自www.cnblogs.com/gered/p/9147233.html