SqlServer事务

一、什么事事务

事务就是一种机制,一个操作序列,包含一组操作指令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求(要么全部执行,要么全部都不执行)

一个事务可以是一条SQL语句,一组SQL语句或整个程序。

 二、事务分类

2.1、显示事务

用 begin transaction 明确指定事务的开始,由 commit transaction 提交事务、rollback transaction 回滚事务到事务结束。

2.2、隐式事务

通过设置 set implicit_transactions on 语句,将隐式事务模式设置为打开。当以隐式事务模式操作时,不必使用 begin transaction 开启事务,当一个事务结束后,这个模式会自动启用下一个事务。只需使用 commit transaction 提交事务或 rollback transaction 回滚事务即可。

2.3、自动提交事务

Sql Server的默认模式,它将每条单独的T-SQL语句视为一个事务。如果成功执行,则自动提交,否则回滚。

三、事务的特性

3.1、原子性

保证任务中的所有操作都执行完毕;否则,事务会在出现错误时终止,并回滚之前所有操作到原始状态。

3.2、一致性

事务必须使数据库从一个一致性状态变换到另一个一致性状态。 

 3.3、持久性

保证任务中的多有操作都执行完毕;否则,事务会在出现错误时终止,并回滚之前所有操作到原始状态。

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

3.4、隔离性

保证不同的事务相互独立、透明地执行。 

四、事务不隔离导致的问题

 以上介绍完事务的四大特性(简称ACID),现在重点来说明下事务的隔离性,当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看乳沟不考虑事务的隔离性,会发生的几种问题:更新丢失(Lost update)、脏读(Dirty Reads)、不可重复读(Non-repeatable Reads)

4.1、更新丢失

两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。

4.2、脏读

 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。

当一个事务正在多次修改某个数据,而在这个事务中这多此的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致 。

-- 用户A向用户B转账1000元,B的钱增加了
update account set money = money+1000 where name='B';
-- 此时A通知B我给你转了1000元,A的钱减少
update account set money = money-1000 where name='A';

当只执行第一条SQL时,A通知B查看账户,B发现确实钱已经到账(此时发生了脏读) 而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

4.3、不可重复读

不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了

  1. 虚读:事务T1读取某一数据后,事务T2对其做了修改,当书屋T1再次读该数据时得到与前一次不同的值。
  2. 幻读:事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的SQL语句相同) 。这是因为在两次查询过程中有另外一个事务插入数据造成的。

五、事务的隔离级别

5.1未提交读取(相当于with(nolock)):第一级别

也称未授权读取:让脏读取,但是不让更新丢失

如果一个事务已经开始写数据,则另一个事务则不允许同时进行写操作,但是允许其他事务读此行数据。

  1. 该隔离级别可以通过“排他写锁” 实现
  2. 缺点:会产生脏读、不可重复读、幻读。

        案例:在教师在上传分数时,你只考了60分,但是老师在录入时(此时开启事务)操作失误将你的分数写成了100分 。

        此时你登录系统查看分数,发现自己考了100分开心不已,到处炫耀

        然后老师发现自己录入错误,并将你的分数更改成60分,完成录入(事务关闭)

        这时你的同桌不信你考了100分,并用你的账号登录了系统查看分数发现你只考了60分,并大肆嘲讽你。

        这里你之前看到的100分就是脏读数据。

解决方法就是采用更高级的隔离机制,如:提交读取

 5.1.1、未提交读取(READ UNCOMMITTED)

READ UNCOMMITTED 事务隔离级别根本没有提供事务事务之间的隔离,它允许违并发性原则的最基本形式之一 --脏读。当一个事务能够读取另一个事务中已经Update 但是尚未Commit 的数据时,“脏读”就不会发生了。READ UNCOMMITTED 读操作不申请锁,运行读取未提交的修改,也就是允许脏读数据,读操作不会影响写操作请求排他锁。

READ UNCOMMMITTED 常应用于:单用户系统;系统中两个事务同时访问同一资源的可能性为零或几乎为零;

5.2、提交读取(Oracle和SQLServer默认的):第二级别

这是大多数数据库系统的默认隔离级别(Oracle和SQLServer默认的)。

        也称为受权读取:允许不可重复读取,但不允许脏读。

这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行

        缺点:会产生不可重复读、幻读。

        案例解读:小明在买吃的时,先查了自己的银行卡余额,发现还剩100元,就想着花掉70用来买吃的,结果在小明查询时小明的老婆从小明的账户上转走了80元。

        这时小明到店付钱时就发现自己就省20元了,这就时不可重复读取的问题。

        解决方法:采用更高级的隔离机制,如可重复读。

通过仅允许一个事务读取另一个事务中已经提交的数据,READ COMMITTED 事务隔离级别防止了“脏读”问题。这是SQL Server中默认的事务隔离级别。

        它是SQL SERVER默认的隔离级别,可以避免读取未提交的数据,隔离级别比READ UNCOMMITTED 未提交读的级别更高;该隔离级别读操作之前首先申请并获得共享锁,允许其他读操作读取该锁定的数据,但是写操作必须等待锁释放,一般读操作读取完就会立刻释放共享锁。

注意:但是由于READ COMMITTED读操作一完成就立即释放共享锁,读操作不会在一个事务过程中保持共享锁,也就是说在一个事务的两个查询得到的结果不一致,这种现象称之为不可重复读。

5.3、可重复读取(相当与(HOLDLOCK)):第三级别

MySQL的默认事务隔离级别。

        可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时间可能出现幻读数据。

这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

        缺点:会产生幻读。

       问题解读:股市忽涨忽跌,老王焦虑不安,按捺不住,想把持有的多种股票全部抛掉。与此 同时,老王老婆听信专家所言,使用老王的账号买了某只神股。

老王抛掉所有股票后,查看自己的持股,猛然发现自己居然还持有一只股票,瞬间觉得一脸懵 逼,这就是幻读导致。 

        解决方案:采用更高级的隔离机制,序列化。

5.4序列化(这是最高的隔离级别):第四级别

        序列化(Serializable):提供严格的事务隔离。

它要求事务序列化执行,事务只能一个接着一个地执行。

仅仅通过“行级锁"是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

        缺点:可以解决并发事务的所有问题,但是效率低下,消耗数据库性能,一般不使用。

        隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为 Read Committed。它能够避免脏读取,而且具有较好的并发性能。

 尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁乐观锁来控制。

5.5快照

(1)SNAPSHOT 在SNAPSHOT隔离级别下,当读取数据时可以保证操作读取的行是事务开始的时候可用的最后提交版本。

(2)同时SNAPSHOT 隔离级别也满足前面的已提交,可重复读,不幻读;该隔离级别使用的不是共享锁,而是行版本控制。

        SNAPSHOT 快照分为 SNAPSHOT和READ COMMITTED SNAPSHOT两种隔离(可以把事务已经提交的行的上一版本保存在TEMPDB数据库中)

 【1】SNAPSHOT隔离级别在逻辑上与SERIALIZABLE类似;

 【2】READ COMMITTED SNAPSHOT隔离级别在逻辑上与READ COMMITTED类似;

        不过在快照隔离级别下读操作不需要申请获得共享锁,所以即便是 数据已经存在排他锁也不影响读操作。而且仍然可以得到和SERIALIZABLE与READ COMMITTED隔离级别类似的一致性;如果目前版本与预期的版本不一致,读操作可以从TEMPDB中获取预期的版本。

        如果启用任何一种基于快照的隔离级别,DELETE和UPDATE语句在做出修改前都会把行的当前版本复制到TEMPDB中,而INSERT语句不需要在TEMPDB中进行版本控制,因为此时还没有行的旧数据。

        无论启用哪种基于快照的隔离级别都会对更新和删除操作产生性能的负面影响,但是有利于提高读取的性能因为读操作不需要获取共享锁。

5.6已提交读快照(READ COMMITTED SNAPSHOT)

READ COMMITTED SNAPSHOT也是基于行版本控制,但是READ COMMITTED SNAPSHOT的隔离级别是读操作之前的最后已提交版本,而不是事务前的已提交版本,有点类似前面的READ COMMITTED能保证已提交读,但是不能保证可重复读,不能避免幻读,但是有比READ COMMITTED隔离级别多出了不需要获取共享锁就可以读取数据。

事务隔离总结

隔离级别解决的并发性问题存在的并发性问题
READ UNCOMMITTED(未提交读取)不适用于并发场合,适合单用户系统Dirty Reads,Non-repeatable Reads,Phantom Reads(脏读、不可重复读、虚读)
READ COMMITTED(提交读取)Dirty Reads(脏读)

Lost Update,Non-repeatble Reads,Phantom Reads(丢失更新、粗可重复读取、虚拟读取)

REPEATABLE READ(可重复读取)on-repeatable Reads(不可 重复读取)Phantom Reads, potentially Deadlocking(幻 像读取,可能死锁)
SERIALIZABLE(序列 化)Phantom Reads(幻 读)Less Data Availability, potentially Deadlocking(数据可用性降低,可能出现死锁)
SNAPSHOT(快照)上述所有并发问题解决的并发性问题事务访问的是虚拟快照,其他事务Committed的 数据对当前事务仍然不可见,也不允许Update被其他事务Update的数据存在的并发性问题
SNAPSHOT(已提交 快照)上述所有并发性问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值