SQL SERVER的锁机制(四)——概述(各种事务隔离级别发生的影响)
六、各种事务隔离级别发生的影响
修改数据的用户会影响同时读取或修改相同数据的其他用户。即这些用户可以并发访问数据。如果数据存储系统没有并发控制,则用户可能会看到以下负面影响:
· 未提交的依赖关系(脏读)
· 不一致的分析(不可重复读)
· 幻读
(一)脏读:
例:张某正在执行某项业务,如下:

begin tran insert tbUnRead select 3,'张三' union select 4,'李四' ---延迟秒,模拟真实交易情形,用于处理业务逻辑 waitfor delay '00:00:05' rollback tran ---此时李某对表中数据进行查询,执行了以下语句: set Transaction isolation level read uncommitted --查询数据 select * from tbUnRead where name like '张%'

则李某可以看到张某所执行的插入语句,把数据添加到了数据库,如下图。

但是张某最终是没有提交事务,而是回滚了事务,所以这条记录并没有真正插入到数据库中。从而发生李某将脏读的数据当成真实的查询结果。
要解决此问题,就是要把数据库的事务隔离级别由未提交读修改成已提交读。只有当查询结果的正确性不是非常重要,或者是隔一段时间查询一次情况下,即使这一次查询结果是错,而下次查询结果是对的,并不会有太大影响,这才适合使用未提交读。
(二)不可重复读
例:张某正在查询数据,如下

set Transaction isolation level read committed begin tran select * from tbUnRead where ID=2 ---延迟秒,模拟真实交易情形,用于处理业务逻辑 waitfor delay '00:00:05' select * from tbUnRead where ID=2 commit tran ---此时李对表中数据进行了更新,如下语句: update tbUnRead set name='Jack_upd' where ID=2

上面的执行语句造成张某在同一个事务内,两次相同的查询条件,查询到不相同的结果(如下图)。

这是由于“已提交读”隔离级别对共享锁保留的时间是:一旦查询完毕就立即释放,而非事务完成才释放。所在张某虽然还在使用事务,事务过程中的所有独占锁都会一直保留,让事务中所更改的数据别人不可进行查询与更改,直到事务完成。但是,被查询的数据在事务过程中是查询完毕就立即释放共享锁,所以别人仍然可以进行修改,造成一笔事务中,两次相同的查询条件,可以得到不相同的结果。最佳的解决方案是将隔离级别设置为“可重复读”。
“可重复读”事务隔离级别,让事务过程中所曾经建立的共享锁都一直保留到事务完成,虽然可以避免“不可重复读”的问题,但是也会导致数据锁定太久,而别人无法读取数据,影响并发率,甚至提高了“死锁”的发生率。
(三)幻读
例:张某正在查询数据,如下

set Transaction isolation level REPEATABLE READ begin tran select * from tbUnRead where ID=3 ---延迟秒,模拟真实交易情形,用于处理业务逻辑 waitfor delay '00:00:05' select * from tbUnRead where ID=3 commit tran --此时李某新增了一条记录,如下语句: INSERT TBUNread select 3,'幻读'

张某已经把隔离级别设置为“可重复读”,虽然是曾经读取的数据,不管是共享锁还是互斥锁都 保留到了事务结束,但是无法阻止其他人运行新增操作,导致第一次查询时没有数据,第二次查询时却有了数据。被称为“幻读”。如下图。

为了避免此类问题,可以将隔离级别设置为“可序列化”,设置之后,则其他人则无法新增数据。
七、各隔离级别所能防止的访问错误
|
隔离级别 |
脏读 |
不可重复读 |
幻读 |
|
未提交读 |
是 |
是 |
是 |
|
已提交读 |
否 |
是 |
是 |
|
可重复读 |
否 |
否 |
是 |
|
快照 |
否 |
否 |
否 |
|
可序列化 |
否 |
否 |
否 |
八、常用锁与事务隔离级别间的交互影响
|
已提交读 |
可重复读 |
快照 |
可序列化 |
|
|
共享 |
读完数据后就释放 |
事务结束才释放 |
不加锁,以版本来控制 |
事务结束才释放 |
|
更新 |
读完数据后就释放或是升级成独占锁 |
读完数据后就释放或是升级成独占锁 |
不加锁,以版本来控制 |
读完数据后就释放或升级成独占锁 |
|
独占 |
事务结束才释放 |
事务结束才释放 |
不加锁,以版本来控制 |
事务结束才释放 |
九、动态锁定管理
数据库引擎使用动态锁定管理策略来控制锁定和系统的最佳成本效益。数据库引擎可以动态调整数据粒度与锁定类型,当使用最低一级的行锁而非更大范围的页锁时,可以降低两个事务要求相同范围的数据锁定的可能性,增强并行访问的能力,可同时服务更多的用户,减小死锁的机率。相反低级锁转为高级锁可以减小系统的资源负担,但会增加并行争用的可能性。
此机制由锁管理器进行管理,每一个锁都需要内存去记录,并且要与锁管理器进行合作,才能完成数据访问操作,你可以想像当表中有100万条记录时,你执行一条没有where语句的update指令时,在默认情况下数据库引擎会采用行锁,但这要记录100万条行锁记录,以及相关的意向共享锁,必定会消耗掉大量的系统资源,当系统资源不足时,数据库引擎会自动提升锁的级别,也就是由行锁提升为页锁,如果资源还是不足,则会再次提升,提升为表锁。
就以上例子来说,如果每个页可以放200条记录,则100万表记录的行锁转为5000个页锁,还省掉了大量的意向共享锁。如果资源还是一足,则可以再次提升锁级别,提升到表锁,这样就只需要一个锁就可以了。
愈大范围的锁花费在管理锁之上的资源就愈少。但相对来说,同时上线并发访问该资源的人数就越少。例如:或采用行锁,则你访问你的记录,我访问我的记录,互相不影响,但如果升级到页锁,则如果你先抢到该分页,而我要访问的记录又恰恰在这一分页上,则我必须要等你释放该分页之后才能访问。如果升级到表锁,则同一时间,该表中的记录只能一个人才能访问,其他人不能访问。如下图。

一般情况下,是不需要手工去设置锁定范围的,可以由Microsoft SQL Server 数据库引擎视情况而定,使用动态锁定策略确定最经济的锁。 执行查询时,数据库引擎会根据架构和查询的特点自动决定最合适的锁。 例如,为了缩减锁定的开销,优化器可能在执行索引扫描时在索引中选择页级锁。
动态锁定具有下列优点:
· 简化数据库管理。 数据库管理员不必调整锁升级阈值。
· 提高性能。 数据库引擎通过使用适合任务的锁使系统开销减至最小。
· 应用程序开发人员可以集中精力进行开发。 数据库引擎将自动调整锁定。
在 SQL Server 2008 中,锁升级的行为已发生改变,其中引入了 LOCK_ESCALATION选项
SQL SERVER的锁机制(四)——概述(各种事务隔离级别发生的影响)的更多相关文章
- (转)SQL SERVER的锁机制(四)——概述(各种事务隔离级别发生的影响)
六.各种事务隔离级别发生的影响 修改数据的用户会影响同时读取或修改相同数据的其他用户.即这些用户可以并发访问数据.如果数据存储系统没有并发控制,则用户可能会看到以下负面影响: · 未提交的依赖关系(脏 ...
- SQL SERVER的锁机制
SQL SERVER的锁机制(一)——概述(锁的种类与范围) SQL SERVER的锁机制(二)——概述(锁的兼容性与可以锁定的资源) SQL SERVER的锁机制(三)——概述(锁与事务隔离级别) ...
- 接上SQL SERVER的锁机制(一)——概述(锁的种类与范围)
二.完整的锁兼容性矩阵(见下图) 对上图的是代码说明:见下图. 三.下表列出了数据库引擎可以锁定的资源. 名称 资源 缩写 编码 呈现锁定时,描述该资源的方式 说明 数据行 RID RID 9 文件编 ...
- (转)SQL SERVER的锁机制(一)——概述(锁的种类与范围)
锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数 ...
- SQL SERVER的锁机制(一)——概述(锁的种类与范围)
锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数 ...
- (转)SQL SERVER的锁机制(三)——概述(锁与事务隔离级别)
五.锁与事务隔离级别 事务隔离级别简单的说,就是当激活事务时,控制事务内因SQL语句产生的锁定需要保留多入,影响范围多大,以防止多人访问时,在事务内发生数据查询的错误.设置事务隔离级别将影响整条连接. ...
- SQL SERVER的锁机制(三)——概述(锁与事务隔离级别)
五.锁与事务隔离级别 事务隔离级别简单的说,就是当激活事务时,控制事务内因SQL语句产生的锁定需要保留多入,影响范围多大,以防止多人访问时,在事务内发生数据查询的错误.设置事务隔离级别将影响整条连接. ...
- 【SQL SERVER】锁机制
锁定是 SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 基本概念 利用SQL Server Profiler观察锁 死锁产生的原因及避免 总结 基本概念 数据库引 ...
- Java中线程的锁和数据库中的事务隔离级别
当涉及到两个或多个线程操作同一个资源时,就会出现锁的问题. 数据库中的某一条记录或者是某一个对象中的字段,可以修改,也可以读取,一般情况下,读取的那个方法应该加锁(即用synchronized互斥), ...
随机推荐
- 数据结构:链表 >> 链表按结点中第j个数据属性排序(冒泡排序法)
创建结点类,链表类,测试类 import java.lang.Object; //结点node=数据date+指针pointer public class Node { Object iprop; p ...
- velocity 框架
Java模板引擎 Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅使用简单的模板语言(template language)来引用由java代码定义的对象 ...
- Python 解释器介绍
举个栗子: -c cmd用法 python -c ' import os ; print ("is ok ") ' 或者(注意引号形式) python -c "impor ...
- Python : locals and globals
Python有两个内置的函数,locals() 和globals(),它们提供了基于字典的访问局部和全局变量的方式.Python使用叫做名字空间的东西来记录变量的轨迹.名字空间只是一个 字典,它的键字 ...
- Windows 8 Stroe Apps 控件
重新想象 Windows 8 Store Apps (3) - 控件之内容控件: ToolTip, Frame, AppBar, ContentControl, ContentPresenter; 容 ...
- vue父传子
父组件传递数据给子组件用props,父组件中使用子组件,子组件用props接收父组件数据. Home父组件代码: <template> <div> {{test}} <! ...
- 类型转化&WCF不同binding的区别
需要使用队列时并且涉及多线程时使用ConcurrentQueue 这个性内比自己使用Queue并且配合lock要好很多 calcFactory = new ChannelFactory<ICal ...
- boost--signal
1.signals2库 signals2库实现了线程安全的观察者模式,在signals2中观察者模式被称为信号/插槽(signals/slots),它是一种函数回调机制.一个信号可以关联一个或多个插槽 ...
- IntelliJ IDEA 2017版 Spring5最基本的bean例子创建
一.简述 SpringBoot是基于spring框架之上的快速开发的框架.Spring4核心就是容器,容器提供了对bean的装配和管理. spring依赖加载: ...
- Arria10_emif
DDR3 由排(Rank),体(Bank),行(Row),列(Column)组成的四维结构. Arria10是第一批支持ddr4的altera Arria10与老器件相比的新结构 (1) 更多的硬( ...