




免费预览已结束,剩余26页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#数据库并发之事务(乐观锁与悲观锁)本文介绍了处理.NET中锁的6种方法,首先我们讨论一下并发性问题,然后讨论处理乐观锁的3种方法,乐观锁不能从根源上解决并发问题,因此后面我们介绍了悲观锁,最后介绍隔离级别如何帮助我们实现悲观锁,每个隔离级别都列举了示例进行说明,使得概念更加清晰。我们为什么需要锁?在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这就会产生冲突,这个就是著名的并发性问题。图 1 并行性问题漫画如何解决并发性问题?借助正确的锁定策略可以解决并发性问题,资源被锁定后,其它进程想要访问它就会被阻止。并发会造成什么样的冲突?并发主要会导致四种常见的问题,详细情况请看下表。问题简要描述解释脏读取当一个事务读取其它完成一半事务的记录时,就会发生脏读取 用户A和用户B看到的值都是5 用户B将值修改为2 用户A看到的值仍然是5,这时就发生了脏读取不可重复读取在每次读数据时,如果你获得的值都不一样,那表明你遇到了不可重复读取问题 用户A看到的值是5 用户B将值改为2 用户A刷新后看到的值仍然是5,这时就发生了不可重复读取虚幻行如果update和delete SQL语句未对数据造成影响,很可能遇到了虚幻行问题 用户A将所有值从5修改为2 用户B使用值2插入一个新记录 用户A查询所有值为2的记录,但却找不到,这时就发生了虚幻行更新丢失一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失 用户A将所有值从5更新为2 用户B将所有值从2更新到5 用户A丢失了他的更新如何解决上述冲突?答案是使用乐观锁或悲观锁,下面将进一步进行阐述。图 2 乐观锁和悲观锁什么是乐观锁?顾名思义,乐观锁假设多个事务相互不会影响对方,换句话说就是,在乐观锁模式下,没有锁操作会得到执行,事务只是验证是否有其它事务修改数据,如果有则进行事务回滚,否则就提交。图 3 乐观锁乐观锁是如何工作的?实现乐观锁的方法有多种,但基本原则都一样,总是少不了下面五个步骤: 记录当前的时间戳 开始修改值 在更新前,检查是否有其他人更新了值(通过检查新旧时间戳实现) 如果不相等就回滚,否则就提交图 4 乐观锁的工作原理实现乐观锁的解决方案在.NET中,实现乐观锁的方法主要有三种: 数据集(Dataset):数据集是实现乐观锁的默认方法,在更新前它会检查新旧值。 时间戳数据类型(timestamp):在你的表中创建一个timestamp数据类型,在更新时,检查旧时间戳是否等于新时间戳。 直接检查新旧值:在更新时检查旧值和新值是否相等,如果不相等就回滚,否则就提交。解决方案1:数据集正如前面所说的,数据集是处理乐观锁的默认方法,下面是一个简单的快照,在Adapter的update函数上有一个调试点,当我移除断点运行update函数时,它抛出如下图所示的并行异常错误。图 5 Update函数执行时抛出的异常错误如果你运行后端分析器,你将会看到更新语句检查当前值和旧值是否相等:exec sp_executesql NUPDATE tbl_items SET AuthorName = p1 WHERE (Id = p2) AND (p3 = 1 AND ItemName IS NULL) OR (ItemName = p4) AND (p5 = 1 AND Type IS NULL) OR (Type = p6) AND (p7 = 1 AND AuthorName IS NULL) OR (AuthorName = p8) AND (p9 = 1 AND Vendor IS NULL) OR (Vendor = p10),Np1 nvarchar(11),p2 int,p3 int,p4 nvarchar(4),p5 int,p6 int,p7 int,p8 nvarchar(18),p9 int,p10 nvarchar(2),p1=Nthis is new,p2=2,p3=0,p4=N1001,p5=0,p6=3,p7=0,p8=NThis is Old Author,p9=0,p10=Nkk在这种情况下,我尝试将“AuthorName”字段值修改为“This is new”,但更新时会检查旧值“This is old author”,下面是比较旧值的精简代码段:,p8=NThis is Old Author解决方案2:使用timestamp数据类型SQL Server有一个数据类型是timestamp,它是实现乐观锁的另一种途径,每次更新SQL Server数据时,时间戳会自动产生一个唯一的二进制数值,时间戳数据类型可用来版本化你的记录更新。图 6 timestamp数据类型为了实现乐观锁,首先需要取得旧的时间戳值,在更新时检查旧的时间戳值是否等于当前时间戳,如:update tbl_items set itemname=itemname where CurrentTimestamp=OldTimeStamp然后检查是否发生了更新操作,如果没有发生更新,则使用SQL Server的raiserror产生一系列错误消息。if(rowcount=0)beginraiserror(Hello some else changed the value,16,10)end如果发生了并发冲突,当你如下图所示这样调用ExecuteNonQuery时,你应该会看到错误传播。图 7 时间戳发生变化,存储过程产生了错误解决方案3:检查旧值和新值许多时候,我们只需要检查相关字段值的一致性,其它字段则可以忽略,在update语句中,我们可以直接做这种比较。update tbl_items set itemname=itemname where itemname=OldItemNameValue但使用乐观锁似乎没有完全解决问题,使用乐观锁只能检查并发性问题,为了从根源上解决并发性问题,我们需要使用悲观锁,因此乐观锁能起到预防作用,而悲观锁则能治愈。什么是悲观锁?悲观锁总是假定会发生并发性/冲突问题,因此会先对记录上锁,然后再更新。图 8 悲观锁如何处理悲观锁?我们可以在SQL Server存储过程中指定IsolationLevel(隔离级别),ADO.NET级别或使用事务范围对象处理悲观锁。使用悲观锁可以获得什么样的锁?使用悲观锁可以获得四种类型的锁:共享(Shared)、独占(Exclusive),更新(Update)和意图(Intent),前两个是真实的锁,后面两个是锁和标记的混合。何时使用允许读允许写共享锁当你只想读,不希望其它事务进行更新时是否独占锁当你想修改数据,同时不希望别人可以读,直到你更新完毕时否否更新锁这是一个混合锁,当你执行的更新操作有多个步骤时使用读阶段是否操作阶段是否更新阶段否否意向锁(请求锁)意向锁是分级的,当你想锁定下级资源时使用,例如,在表上的一个共享意向锁意味着共享锁是针对页面和表中的行的,不适用不适用模式锁当你修改表结构时使用否否大数据块更新锁当你执行大数据块更新时使用表级(否)表级(否)详解让人困惑的更新锁其它锁都好理解,唯独更新锁让人迷糊,因为它混合了锁和标记,在更新前我们首先要读取记录,在读取期间锁是共享的,而在真正更新时,我们需要独占锁,更新锁是非常短暂的。图 9 更新时用到的几种锁不同隔离级别之间的差异,以及何时使用它们有4种事务隔离级别,下表列出了这4种隔离级别及其使用时间。隔离级别读更新插入读未提交的读取未提交的数据允许允许读已提交的(默认)读取已提交的数据允许允许重复读读取已提交的数据不允许允许序列化读取已提交的数据不允许不允许如何指定隔离级别?隔离级别是关系数据库的一个功能,也就是说,它基本上只与SQL Server相关,而与ADO.NET,EF或LINQ是没有什么关系的,但你可以在这些组件上设置隔离级别。图 10 隔离级别中间层:在中间层,你可以使用事务范围对象指定隔离级别。TransactionOptions TransOpt = New TransactionOptions();TransOpt.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TransOptions)ADO.NET:在ADO.NET中你可以使用SqlTransaction对象指定事务隔离级别。SqlTransaction objtransaction = objConnection.BeginTransaction(System.Data.IsolationLevel.Serializable);SQL Server:你也可以在TSQL中使用“SET TRANSACATION ISOLATION LEVEL”指定隔离级别。SET TRANSACTION ISOLATION LEVEL READ COMMITTED;事务隔离级别与它能解决的并发性问题之间的对应关系读已提交的重复读序列化读未提交的脏读取能解决能解决能解决不能丢失更新不能能解决能解决不能非重复读不能能解决能解决不能幻想行不能不能能解决不能解决方案4:使用“读已提交的”解决“脏读取”问题关于“读已提交的”的一些关键点: 它是SQL Server默认的事务隔离级别。 它只读取已提交的数据,换句话说就是,任何未提交的数据它都会置之不理,直到数据提交为止,下图对其进行了详细解释,你也可以看到更新。图 11 读已提交模式解析如果你想看到上图所述的情况,只需要按照下面的步骤做就可以了: 打开两个查询窗口,执行一个更新事务,但不提交; 在第二个窗口中执行查询时,会显示如下图所示的查询被阻止的提示。图 12 查询被阻止,直到更新事务提交后才能执行“读已提交的”对立面是“读未提交的”吗?是的,读未提交的是读已提交的对立面,当你设置读未提交的事务隔离级别时,未提交的数据也被读取了。关于“读已提交的”关键点: 未提交的是可见的,因此脏读取是可能的; 没有锁被抓住; 当锁不重要时很有用,更重要的是并发性和吞吐量。如果你也想测试一下,试试下面的SQL语句,它执行一个更新然,在等待20秒后回滚,在此期间如果你执行查询,返回的是未提交的数据,但20秒后,你再查询,返回的将会以前的旧数据,因为提交的数据已回滚。set transaction isolation level read uncommittedBegin TranUpdate customer set CustomerName=Changed where CustomerCode=1001WAITFOR DELAY 000:00:20rollback transet transaction isolation level read uncommittedselect * from Customer where CustomerCode=1001解决方案5:使用重复读解决丢失更新和非重复读给重复读设置隔离级别后,其他人就不能读取和更新数据,关于重复读隔离级别的关键点包含: 当为查询设置重复事务隔离级别时,只读取已提交的数据。 当你使用重复读选择一条记录时,其它事务将不能更新该条记录,但查询是可以的。 如果在更新查询中设置了可重复事务,必须要等到事务完成才能读和更新相同的记录。 当选择和更新查询被设置为可重复读,其它事务可以插入新记录,换句话说就是虚幻行是可能的。如果你想测试这个隔离级别,执行下面的语句,然后尝试查询和更新查询,它们都将被阻止,50秒后你才能看到数据。set transaction isolation level repeatable readBegin TranUpdate customer set CustomerName=Changed where CustomerCode=1001WAITFOR DELAY 000:00:50rollback tran如果在重复读模式下执行下面的查询语句,在50秒内你啥也干不了,直到事务完成后你才能得到查询结果。set transaction isolation level repeatable readbegin transelect * from Customer where CustomerCode=1001WAITFOR DELAY 000:00:50commit tran注意,在此期间你可以添加CustomerCode=1001的新记录,换句话说就是虚幻行是可能的。解决方案6:使用序列化隔离级别解决虚幻行问题这是最高级的隔离级别,在此期间,其它事务是不能更新,查询和插入记录的,关于序列化事务的一些关键点包含: 当隔离级别是序列化时,没有其它事务可以插入,更新,删除或查询。 会出现许多阻塞,但所有并发性问题都能得到解决。补充:锁就是防止其他事务访问指定的资源的手段。锁是实现并发控制的主要方法,是多个用户能够同时操纵同一个数据库中的数据而不发生数据不一致现象的重要保障。一般来说,锁可以防止脏读、不可重复读和幻觉读。事务并发产生的问题: 脏读:一个事务读取到了另外一个事务没有提交的数据 事务1:更新一条数据 -事务2:读取事务1更新的记录 事务1:调用commit进行提交 *此时事务2读取到的数据是保存在数据库内存中的数据,称为脏读。 *读到的数据为脏数据 详细解释: 脏读就是指:当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时, 另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个 事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。 不可重复读:在同一事务中,两次读取同一数据,得到内容不同 事务1:查询一条记录 -事务2:更新事务1查询的记录 -事务2:调用commit进行提交 事务1:再次查询上次的记录 *此时事务1对同一数据查询了两次,可得到的内容不同,称为不可重复读 幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同 事务1:查询表中所有记录 -事务2:插入一条记录 -事务2:调用commit进行提交 事务1:再次查询表中所有记录 *此时事务1两次查询到的记录是不一样的,称为幻读 详细解释: 幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改, 这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表 中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行, 就好象发生了幻觉一样。处理以上隔离级别的问题,采用如下方是:事务隔离五种级别: TRANSACTION_NONE 不使用事务。 TRANSACTION_READ_UNCOMMITTED 允许脏读。 TRANSACTION_READ_COMMITTED 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别 TRANSACTION_REPEATABLE_READ 可以防止脏读和不可重复读, TRANSACTION_SERIALIZABLE 可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率以上的五个事务隔离级别都是在Connection接口中定义的静态常量,使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。 如:con.setTransactionIsolation(Connection.REPEATABLE_READ);注意:事务的隔离级别受到数据库的限制,不同的数据库支持的的隔离级别不一定相同 1 脏读:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题。 但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。 2 不可重复读:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题 3 幻读问题:采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻影读问题,在这里有个描述范围锁的文章当执行不同的隔离级别时,可能会发生各种各样不同的问题。下面对它们进行总结并举例说明:幻读 :幻读发生在当两个完全相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同。发生的情况:没有范围锁。说明:什么是共享锁?什么是排他锁?共享锁:如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。排他锁:如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。简要说明为什么会发生死锁?解决死锁的主要方法是什么?若干事务相互等待释放封锁,就陷入无限期等待状态,系统就进入死锁解决死锁的方法应从预防和解除的两个方面着手:(1)死锁的预防方法:要求每一个事务必须一次封锁所要使用的全部数据(要么全成功,要么全不成功)规定封锁数据的顺序,所有事务必须按这个顺序实行封锁。(2)允许死锁发生,然后解除它,如果发现死锁,则将其中一个代价较小的事物撤消,回滚这个事务,并释放此事务持有的封锁,使其他事务继续运行。例子:事务1 事务2 SELECT* FROMusersWHEREage BETWEEN 10 AND 30 ; INSERTINTOusers VALUES(3, Bob, 27); SELECT* FROMusers WHEREage BETWEEN10AND30;如何避免:实行序列化隔离模式,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 公考安徽真题2025
- 2025年宜兴市事业单位考试真题
- 农发行抚州市临川区2025秋招小语种岗笔试题及答案
- 2025年乡村旅游发展报告:文旅融合视角下的乡村旅游与乡村旅游与乡村旅游规划
- 2025年食品安全追溯技术在食品行业食品安全信用体系建设中的应用报告
- 平硐盲竖井开拓课件
- 2025年新能源汽车充电桩智能化升级改造技术报告
- 往年统招试卷真题及答案
- 2025网络文学IP产业链全链路开发模式创新与价值实现路径研究
- 2025年江苏省中考试试题及答案
- 餐饮库房管理流程
- 市政工程监理大纲投标方案(技术方案)
- 技术经纪人(初级)考试试题(附答案)
- 幕墙UHPC施工专项方案 (评审版)
- 苏东坡人物介绍下载
- 2025届高三二轮复习+生态脆弱区的综合治理
- 《电力储能运行人员培训规范》
- 轻钢屋面工程施工方案
- DB3702T 31-2023 未成年人家庭监护能力评估工作规范
- 2024-2025年历年成人高考民法真题及复习资料
- 幼儿园课程教研活动
评论
0/150
提交评论