设为首页 收藏本站
查看: 1985|回复: 0

[经验分享] 专注,勤学,慎思。戒骄戒躁,谦虚谨慎

[复制链接]

尚未签到

发表于 2017-12-13 21:46:26 | 显示全部楼层 |阅读模式
  本文出处:http://www.cnblogs.com/wy123/p/7218316.html
  (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误进行修正或补充,无他)
  数据库中的事物是具有原子性(Atomicity),一致性(Consistemcy),隔离性(Isolation),持久性(Durability)四个特征。
  在上述四个特性中的一致性和隔离性的实现中,是通过锁来实现对相同数据的访问隔离的。
  事物的隔离级别又可以影响锁的申请和时间的时机。
  因此,不同的事物隔离级别又可以对锁的申请和释放产生不同的影响,因此,在对数据库做事物控制的时候需要了解隔离级别对事物的影响。
  SQL Server实现SQL99标准规定的事务的四个隔离级别(未提交读,已提交读,可重复读,序列化)之外,另外增加了两个隔离级别(快照个基于行版本的已提交读隔离级别)。
  不同的隔离级别对控制脏读,不可重复读,幻读有一定的控制,也会并发有一定程度的影响,
  隔离级别越低,并发性越高,但是产生脏读,不可重复读,幻读等可能性越大;随着事物隔离级别的提交,可以控制脏读,不可重复读,以及幻读的现象,但是并发性也会随之降低。
  事物隔离级别和执行计划都可以影响锁(范围)的申请和释放时机,本文暂不讨论执行计划对锁申请的影响,仅在隔离级别上说明锁的申请和释放。
  以下简单介绍SQL Server中的六个隔离级别以及每个隔离级别的特征,在此基础上说明每个隔离级别可能存在的问题解决方法。
  未提交读
  运行当前Session读取其他事务已修改但是尚未提交的数据,也即当前Session可以读取到“脏数据”。
  当前Session不会对读取的数据加共享锁。
  set transaction isolation level read uncommitted;
  或者
  select * from table with(nolock)
  特点:未提交读是最低的一种隔离级别。
  存在的问题:脏读,不一致读,幻读等。
  如下是未提交度的存在脏读一种演示(当然也会存在不一致读,幻读等情况)。
DSC0000.png

  已提交读
  set transaction isolation level read committed;
  或者
  select * from table  默认人就是已提交读
  运行当前Session不能读取其他事务已修改但是尚未提交的数据。
  如果其他事务提对当前Session读取的数据有修改且尚未提交,当前Session被阻塞。
  原因是在以已提交读隔离级别情况下:当前Session会对读取的数据加共享锁,如果遇到读取的数据尚未提交,当前查询被阻塞。
  特点:相比为提交读隔离级别,解决了未提交读隔离级别下的读取“脏数据”的问题,
  存在的问题:存在不可重复度或者幻读的问题。
  已提交读隔离级别下存在不可重复读的现象(两次读取的同一行数据结果不一致)
DSC0001.png

  不可重复读隔离级别下存在的幻读现象(一个事物中,同样的条件,读到的数据行数不一致)
DSC0002.png

  可重复读
  set transaction isolation level repeatable read;
  运行当前Session不能读取其他事务已修改但是尚未提交的数据,并且当前Session运行期间,其他Session不能修改当前Session读取到的数据
  也就是说,当前Session运行期间,读取到的数据是被加了共享锁的,所加的共享锁一直保持,直到事务提交的时候才释放。
  相比已提交读最大的特点就是事务运行期间,共享锁将一直保持,直到当前Session事务提交,
  因此可以保持当前Session读取到的数据不被其他Session修改,所以就不存在两次读取的数据不一致的现象。
  可重复读隔离级别解决了不可重复读的问题,但依旧存在幻读的情况。
  特点:相比前一种隔离级别,可重复读解决了已提交读隔离级别的不可重复读的问题,也即两次读取的同一行数据是一致的
  存在的问题:相比已提交读,依旧存在幻读的问题。
  如下是可重复读隔离级别的幻读的现象,也即在同一个事物的两次读取期间,其他事物可以写入当前事物读取的数据(范围)
DSC0003.png

  可序列化
  当前Session不能读取其他Session已修改但未提交的数据(不允许脏读)
  当前Session读取的数据上的共享锁一直保持直到事务提交(可重复读)
  当前Session事务提交之前,其他Session不能插入当前Session中读取的键值(解决了幻读的问题)
  set transaction isolation level serializable
  或者开启事务之后对表加holdlock提示

  select * from table with(holdlock) where>  可序列化解决了另外一个非常经典的问题,使用update table with(holdlock) 或者select * from table with(xlock,holdlock),并发情况下的“存在则更新不存在则插入”重复插入的问题。
  参考:http://www.cnblogs.com/TeyGao/p/6929246.html
  可序列化锁定的原理是加范围锁的方式来实现的,当一个Session发起了请求之后,对于当前Session范围内的数据,不管是否存在,都加一个共享锁。

  比如在可序列化的隔离级别之下,select * from table with where>  在Session执行期间,SQL Server会锁定 100<=id<= 120这个范围的数据,不管表中这个区间是否存在数据, 都锁定这个Id的范围,不允许该Id范围的数据写入。
  也即100<=id<= 120这个范围被所锁定(无法增加删除或者修改这个范围的数据)
  可序列化隔离级别解决了幻读的问题,也就是说,当前事物的两次读中间,其他Session对当前Session读取数据范围之内的数据修改的时候,会被阻塞,直到当前事物提交。
DSC0004.png

  基于行版本控制的隔离级别
  默认隔离级别,也即已提交读隔离级别下,存在一个明显的问题就是写会阻塞读,也就是说,一个写数据的事物未提交之前,会阻塞其他事物对当前操作数据的读取,直到当前写事物的操作提交。
  基于行版本控制的已提交读隔离级别下,写不会阻塞读,写数据的事物未提交之前,会将修改的数据之前的版本,写入临时数据库,
  读数据的事物在读取的时候,发现要读取的数据被修改,会转向临时库中读取出来一个写事物修改数据之前的版本,这样可以在一定程度上提高并发性(当然临时库会承担一定的压力)。
  SQL Server有两种基于行版本控制的隔离级别:快照隔离级别(snapshot)和基于行版本控制的已提交读隔离级别(read_committed_snapshot)
  两种行版本控制分别要基于数据级别开启allow_snapshot_isolation和read_committed_snapshot
  (1)快照隔离级别(snapshot)
  数据库级别设置快照隔离级别
  alter database Test set allow_snapshot_isolation on;
DSC0005.png

  Session级别设置快照隔离级别:set transaction isolation level snapshot
  快照隔离级别最大的特点是,当前Session读取其他事物修改的数据的时候,不会被阻塞,读取的是其他事物已经修改,但是尚未提交的数据
  但是当前事物尝试修改“在其他其他事物中提交修改之后的数据”,会报错(快照隔离事务由于更新冲突已终止)。
  具体过程如下,从时间的维度来看,步骤如下
  1)Session2 开启事物,修改Id =1的数据,暂不提交
  2)Session1 读取id=1的数据,不会被阻塞,读取到的是Session2修改之前的数据的版本
  3)Session2修改Id =1的数据之后,事物提交
  4)Session1尝试修改Id=1的数据,报错
DSC0006.png

  实际操作上看,如下
DSC0007.png

  (2)基于行版本控制的已提交读隔离级别(read_committed_snapshot)
  数据库级别设置为基于行版本控制的已提交读隔离级
  alter database Test set read_committed_snapshot on;
  go
DSC0008.png

  --将当前事物设置为已提交读快照隔离级别
  set transaction isolation level read committed
  快照隔离级别最大的特点是,当前Session读取其他事物修改的数据的时候,不会被阻塞,读取的是其他事物已经修改,但是尚未提交的数据
  与快照隔离级别相对,当前Session尝试修改“在其他其他Session中提交修改之后的数据”,可以成功提交。
  具体过程如下,从时间的维度来看,步骤如下
  1)Session2 开启事物,修改Id =1的数据,暂不提交
  2)Session1 读取id=1的数据,不会被阻塞,读取到的是Session2修改之前的数据的版本
  3)Session2修改Id =1的数据之后,事物提交
  4)Session1尝试修改Id=1的数据,成功提交,
  基于行版本控制的已提交读隔离级别最大的特点是,当前读取的数据是,其他Session已修改尚未提交之前的版本,但是当前事物尝试修改时,可以成功提交
  这样一来,就忽略掉了当前事物运行期间,其他事物修改且提交的那个版本的数据,有点绕,需要慢慢理解。
  行版本控制的已提交读隔离级别的问题也很明显,当前Session读取数据的时候,是其他事物修改之前的版本,当前Session对读取到的数据可以在其他事物提价之前的版本上执行修改,
  而忽略了当前Session在读和写的间隔期间,其他Session修改并且提交事物的影响,为此可能会产生一定程度的影响。
  从时间维度上看如下图所示
DSC0009.png

  具体执行现象如下:
  存在的问题就是,Session1第一次读取的时候,读取的Id = 1数据的那么是AAA,实际上此时其他Session2已经将Id = 1的那么修改为了Update_AAA,
  随后Session2事物提交,当前Session执行修改的时候,忽略了Session2修改后的数据,可以直接将数据修改为AAA+++
  需要注意的是,Session1修改成功的前提是Session2的事物提交,如果Session2修改事物没有提交,Session1的修改操作被阻塞。
  截图中第一行的备注没有修改过来,应该是快照已提价读隔离级别
DSC00010.png

  总结:
  本文简单阐述了SQL Server中的几种隔离级别,SQL Server实现了SQL99定义的四个标准隔离级别,并且额外实现了两个快照隔离级别。
  需要说明的是,不同的DBMS的默认隔离级别和对隔离级别的实现是不完全一样的,也不一定是完全按照SQL99定义的四个标准隔离级别来实现的,
  因此在做事物控制的时候,需要了解具体的隔离级别以及具体特性。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-423821-1-1.html 上篇帖子: SQL Server中【case...end】的用法 下篇帖子: Love in coding...
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表