




已阅读5页,还剩97页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#数据库事务原理及实践分类:C#2012-03-01 22:53137人阅读评论(0)收藏举报数据库c#sql serverfiledatabaseexception什么是数据库事务数据库事务是指作为单个逻辑工作单元执行的一系列操作。设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:更新客户所购商品的库存信息保存客户付款信息-可能包括与银行系统的交互生成订单并且保存到数据库中更新用户相关信息,例如购物数量等等正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态-库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术。数据库事务的ACID属性事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性:原子性事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。一致性事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如B树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。隔离性由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。持久性事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。DBMS的责任和我们的任务企业级的数据库管理系统(DBMS)都有责任提供一种保证事务的物理完整性的机制。就常用的SQL Server2000系统而言,它具备锁定设备隔离事务、记录设备保证事务持久性等机制。因此,我们不必关心数据库事务的物理完整性,而应该关注在什么情况下使用数据库事务、事务对性能的影响,如何使用事务等等。本文将涉及到在.net框架下使用C#语言操纵数据库事务的各个方面。体验SQL语言的事务机制作为大型的企业级数据库,SQL Server2000对事务提供了很好的支持。我们可以使用SQL语句来定义、提交以及回滚一个事务。如下所示的SQL代码定义了一个事务,并且命名为MyTransaction(限于篇幅,本文并不讨论如何编写SQL语言程序,请读者自行参考相关书籍):DECLARE TranName VARCHAR(20)SELECT TranName = MyTransactionBEGIN TRANSACTION TranNameGOUSE pubsGOUPDATE royschedSET royalty = royalty * 1.10WHERE title_id LIKE Pc%GOCOMMIT TRANSACTION MyTransactionGO这里用到了SQL Server2000自带的示例数据库pubs,提交事务后,将为所有畅销计算机书籍支付的版税增加10%。打开SQL Server2000的查询分析器,选择pubs数据库,然后运行这段程序,结果显而易见。可是如何在C#程序中运行呢?我们记得在普通的SQL查询中,一般需要把查询语句赋值给SalCommand.CommandText属性,这里也就像普通的SQL查询语句一样,将这些语句赋给SqlCommand.CommandText属性即可。要注意的一点是,其中的GO语句标志着SQL批处理的结束,编写SQL脚本是需要的,但是在这里是不必要的。我们可以编写如下的程序来验证这个想法:/TranSql.csusing System;using System.Data;using System.Data.SqlClient;namespace Aspcnpublic class DbTranSqlfile:/将事务放到SQL Server中执行public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();trymyComm.Connection=myConn;myComm.CommandText=DECLARE TranName VARCHAR(20) ;myComm.CommandText+=SELECT TranName = MyTransaction ;myComm.CommandText+=BEGIN TRANSACTION TranName ;myComm.CommandText+=USE pubs ;myComm.CommandText+=UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE Pc% ;myComm.CommandText+=COMMIT TRANSACTION MyTransaction ;myComm.ExecuteNonQuery();catch(Exception err)throw new ApplicationException(事务操作出错,系统信息:+err.Message);finallymyConn.Close();file:/获取数据连接private SqlConnection GetConn()string strSql=Data Source=localhost;Integrated Security=SSPI;user id=sa;password=;SqlConnection myConn=new SqlConnection(strSql);return myConn;public class Testpublic static void Main()DbTranSql tranTest=new DbTranSql();tranTest.DoTran();Console.WriteLine(事务处理已经成功完成。);Console.ReadLine();注意到其中的SqlCommand对象myComm,它的CommandText属性仅仅是前面SQL代码字符串连接起来即可,当然,其中的GO语句已经全部去掉了。这个语句就像普通的查询一样,程序将SQL文本事实上提交给DBMS去处理了,然后接收返回的结果(如果有结果返回的话)。很自然,我们最后看到了输出事务处理已经成功完成,再用企业管理器查看pubs数据库的roysched表,所有title_id字段以PC开头的书籍的royalty字段的值都增加了0.1倍。这里,我们并没有使用ADO.net的事务处理机制,而是简单地将执行事务的SQL语句当作普通的查询来执行,因此,事实上该事务完全没有用到.net的相关特性。了解.net中的事务机制如你所知,在.net框架中主要有两个命名空间(namespace)用于应用程序同数据库系统的交互:System.Data.SqlClient和System.Data.OleDb。前者专门用于连接Microsoft公司自己的SQL Server数据库,而后者可以适应多种不同的数据库。这两个命名空间中都包含有专门用于管理数据库事务的类,分别是System.Data.SqlClient.SqlTranscation类和System.Data.OleDb.OleDbTranscation类。就像它们的名字一样,这两个类大部分功能是一样的,二者之间的主要差别在于它们的连接机制,前者提供一组直接调用SQL Server的对象,而后者使用本机OLE DB启用数据访问。事实上,ADO.net事务完全在数据库的内部处理,且不受Microsoft分布式事务处理协调器(DTC)或任何其他事务性机制的支持。本文将主要介绍System.Data.SqlClient.SqlTranscation类,下面的段落中,除了特别注明,都将使用System.Data.SqlClient.SqlTranscation类。事务的开启和提交现在我们对事务的概念和原理都了然于心了,并且作为已经有一些基础的C#开发者,我们已经熟知编写数据库交互程序的一些要点,即使用SqlConnection类的对象的Open()方法建立与数据库服务器的连接,然后将该连接赋给SqlCommand对象的Connection属性,将欲执行的SQL语句赋给它的CommandText属性,于是就可以通过SqlCommand对象进行数据库操作了。对于我们将要编写的事务处理程序,当然还需要定义一个SqlTransaction类型的对象。并且看到SqlCommand对象的Transcation属性,我们很容易想到新建的SqlTransaction对象应该与它关联起来。基于以上认识,下面我们就开始动手写我们的第一个事务处理程序。我们可以很熟练地写出下面这一段程序:/DoTran.csusing System;using System.Data;using System.Data.SqlClient;namespace Aspcnpublic class DbTranfile:/执行事务处理public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();SqlTransaction myTran=new SqlTransaction();trymyComm.Connection=myConn;myComm.Transaction=myTran;file:/定位到pubs数据库myComm.CommandText=USE pubs;myComm.ExecuteNonQuery();file:/更新数据file:/将所有的计算机类图书myComm.CommandText=UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE Pc%;myComm.ExecuteNonQuery();/提交事务myTran.Commit();catch(Exception err)throw new ApplicationException(事务操作出错,系统信息:+err.Message);finallymyConn.Close();file:/获取数据连接private SqlConnection GetConn()string strSql=Data Source=localhost;Integrated Security=SSPI;user id=sa;password=;SqlConnection myConn=new SqlConnection(strSql);return myConn;public class Testpublic static void Main()DbTran tranTest=new DbTran();tranTest.DoTran();Console.WriteLine(事务处理已经成功完成。);Console.ReadLine();显然,这个程序非常简单,我们非常自信地编译它,但是,出乎意料的结果使我们的成就感顿时烟消云散:error CS1501:重载SqlTransaction方法未获取0参数是什么原因呢?注意到我们初始化的代码:SqlTransaction myTran=new SqlTransaction();显然,问题出在这里,事实上,SqlTransaction类并没有公共的构造函数,我们不能这样新建一个SqlTrancaction类型的变量。在事务处理之前确实需要有一个SqlTransaction类型的变量,将该变量关联到SqlCommand类的Transcation属性也是必要的,但是初始化方法却比较特别一点。在初始化SqlTransaction类时,你需要使用SqlConnection类的BeginTranscation()方法:SqlTransaction myTran; myTran=myConn.BeginTransaction();该方法返回一个SqlTransaction类型的变量。在调用BeginTransaction()方法以后,所有基于该数据连接对象的SQL语句执行动作都将被认为是事务MyTran的一部分。同时,你也可以在该方法的参数中指定事务隔离级别和事务名称,如:SqlTransaction myTran;myTran=myConn.BeginTransaction(IsolationLevel.ReadCommitted,SampleTransaction);关于隔离级别的概念我们将在随后的内容中探讨,在这里我们只需牢记一个事务是如何被启动,并且关联到特定的数据链接的。先不要急着去搞懂我们的事务都干了些什么,看到这一行:myTran.Commit();是的,这就是事务的提交方式。该语句执行后,事务的所有数据库操作将生效,并且为数据库事务的持久性机制所保持-即使系统在这以后发生致命错误,该事务对数据库的影响也不会消失。对上面的程序做了修改之后我们可以得到如下代码(为了节约篇幅,重复之处已省略,请参照前文):/DoTran.csfile:/执行事务处理public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();file:/SqlTransaction myTran=new SqlTransaction();file:/注意,SqlTransaction类无公开的构造函数SqlTransaction myTran;file:/创建一个事务myTran=myConn.BeginTransaction();tryfile:/从此开始,基于该连接的数据操作都被认为是事务的一部分file:/下面绑定连接和事务对象myComm.Connection=myConn;myComm.Transaction=myTran; file:/定位到pubs数据库myComm.CommandText=USE pubs;myComm.ExecuteNonQuery();/更新数据file:/将所有的计算机类图书myComm.CommandText=UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE Pc%;myComm.ExecuteNonQuery();file:/提交事务myTran.Commit();catch(Exception err)throw new ApplicationException(事务操作出错,系统信息:+err.Message);finallymyConn.Close();到此为止,我们仅仅掌握了如何开始和提交事务。下一步我们必须考虑的是在事务中可以干什么和不可以干什么。另一个走向极端的错误满怀信心的新手们可能为自己所掌握的部分知识陶醉不已,刚接触数据库库事务处理的准开发者们也一样,踌躇满志地准备将事务机制应用到他的数据处理程序的每一个模块每一条语句中去。的确,事务机制看起来是如此的诱人简洁、美妙而又实用,我当然想用它来避免一切可能出现的错误我甚至想用事务把我的数据操作从头到尾包裹起来。看着吧,下面我要从创建一个数据库开始:using System;using System.Data;using System.Data.SqlClient;namespace Aspcnpublic class DbTranfile:/执行事务处理public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();SqlTransaction myTran;myTran=myConn.BeginTransaction();file:/下面绑定连接和事务对象myComm.Connection=myConn;myComm.Transaction=myTran;file:/试图创建数据库TestDBmyComm.CommandText=CREATE database TestDB;myComm.ExecuteNonQuery();file:/提交事务myTran.Commit();file:/获取数据连接private SqlConnection GetConn()string strSql=Data Source=localhost;Integrated Security=SSPI;user id=sa;password=;SqlConnection myConn=new SqlConnection(strSql);return myConn;public class Testpublic static void Main()DbTran tranTest=new DbTran();tranTest.DoTran();Console.WriteLine(事务处理已经成功完成。);Console.ReadLine();/-未处理的异常:System.Data.SqlClient.SqlException:在多语句事务内不允许使用CREATE DATABASE语句。at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()at Aspcn.DbTran.DoTran()at Aspcn.Test.Main()注意,如下的SQL语句不允许出现在事务中:ALTER DATABASE修改数据库BACKUP LOG备份日志CREATE DATABASE创建数据库DISK INIT创建数据库或事务日志设备DROP DATABASE删除数据库DUMP TRANSACTION转储事务日志LOAD DATABASE装载数据库备份复本LOAD TRANSACTION装载事务日志备份复本RECONFIGURE更新使用sp_configure系统存储过程更改的配置选项的当前配置(sp_configure结果集中的config_value列)值。RESTORE DATABASE还原使用BACKUP命令所作的数据库备份RESTORE LOG还原使用BACKUP命令所作的日志备份UPDATE STATISTICS在指定的表或索引视图中,对一个或多个统计组(集合)有关键值分发的信息进行更新除了这些语句以外,你可以在你的数据库事务中使用任何合法的SQL语句。事务回滚事务的四个特性之一是原子性,其含义是指对于特定操作序列组成的事务,要么全部完成,要么就一件也不做。如果在事务处理的过程中,发生未知的不可预料的错误,如何保证事务的原子性呢?当事务中止时,必须执行回滚操作,以便消除已经执行的操作对数据库的影响。一般的情况下,在异常处理中使用回滚动作是比较好的想法。前面,我们已经得到了一个更新数据库的程序,并且验证了它的正确性,稍微修改一下,可以得到:/RollBack.csusing System;using System.Data;using System.Data.SqlClient;namespace Aspcnpublic class DbTranfile:/执行事务处理public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();SqlTransaction myTran;file:/创建一个事务myTran=myConn.BeginTransaction();file:/从此开始,基于该连接的数据操作都被认为是事务的一部分file:/下面绑定连接和事务对象myComm.Connection=myConn;myComm.Transaction=myTran;tryfile:/定位到pubs数据库myComm.CommandText=USE pubs;myComm.ExecuteNonQuery();myComm.CommandText=UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE Pc%;myComm.ExecuteNonQuery();file:/下面使用创建数据库的语句制造一个错误myComm.CommandText=Create database testdb;myComm.ExecuteNonQuery();myComm.CommandText=UPDATE roysched SET royalty = royalty * 1.20 WHERE title_id LIKE Ps%;myComm.ExecuteNonQuery();file:/提交事务myTran.Commit();catch(Exception err)myTran.Rollback();Console.Write(事务操作出错,已回滚。系统信息:+err.Message);file:/获取数据连接private SqlConnection GetConn()string strSql=Data Source=localhost;Integrated Security=SSPI;user id=sa;password=;SqlConnection myConn=new SqlConnection(strSql);return myConn;public class Testpublic static void Main()DbTran tranTest=new DbTran();tranTest.DoTran();Console.WriteLine(事务处理已经成功完成。);Console.ReadLine();首先,我们在中间人为地制造了一个错误使用前面讲过的Create database语句。然后,在异常处理的catch块中有如下语句:myTran.Rollback();当异常发生时,程序执行流跳转到catch块中,首先执行的就是这条语句,它将当前事务回滚。在这段程序可以看出,在Create database之前,已经有了一个更新数据库的操作将pubs数据库的roysched表中的所有title_id字段以“PC”开头的书籍的royalty字段的值都增加0.1倍。但是,由于异常发生而导致的回滚使得对于数据库来说什么都没有发生。由此可见,Rollback()方法维护了数据库的一致性及事务的原子性。使用存储点事务只是一种最坏情况下的保障措施,事实上,平时系统的运行可靠性都是相当高的,错误很少发生,因此,在每次事务执行之前都检查其有效性显得代价太高绝大多数的情况下这种耗时的检查是不必要的。我们不得不想另外一种办法来提高效率。事务存储点提供了一种机制,用于回滚部分事务。因此,我们可以不必在更新之前检查更新的有效性,而是预设一个存储点,在更新之后,如果没有出现错误,就继续执行,否则回滚到更新之前的存储点。存储点的作用就在于此。要注意的是,更新和回滚代价很大,只有在遇到错误的可能性很小,而且预先检查更新的有效性的代价相对很高的情况下,使用存储点才会非常有效。使用.net框架编程时,你可以非常简单地定义事务存储点和回滚到特定的存储点。下面的语句定义了一个存储点“NoUpdate”:myTran.Save(NoUpdate);当你在程序中创建同名的存储点时,新创建的存储点将替代原有的存储点。在回滚事务时,只需使用Rollback()方法的一个重载函数即可:myTran.Rollback(NoUpdate);下面这段程序说明了回滚到存储点的方法和时机:using System;using System.Data;using System.Data.SqlClient;namespace Aspcnpublic class DbTranfile:/执行事务处理public void DoTran()file:/建立连接并打开SqlConnection myConn=GetConn();myConn.Open();SqlCommand myComm=new SqlCommand();SqlTransaction myTran;file:/创建一个事务myTran=myConn.BeginTransaction();file:/从此开始,基于该连接的数据操作都被认为是事务的一部分file:/下面绑定连接和事务对象myComm.Connection=myConn;myComm.Transaction=myTran;trymyComm.CommandText=use pubs;myComm.ExecuteNonQuery();myTran.Save(NoUpdate);myComm.CommandText=UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE Pc%;myComm.ExecuteNonQuery();file:/提交事务myTran.Commit();catch(Exception err)file:/更新错误,回滚到指定存储点myTran.Rollback(NoUpdate);throw new ApplicationException(事务操作出错,系统信息:+err.Message);file:/获取数据连接private SqlConnection GetConn()string strSql=Data Source=localhost;Integrated Security=SSPI;user id=sa;password=;SqlConnection myConn=new SqlConnection(strSql);return myConn;public class Testpublic static void Main()DbTran tranTest=new DbTran();tranTest.DoTran();Console.WriteLine(事务处理已经成功完成。);Console.ReadLine();很明显,在这个程序中,更新无效的几率是非常小的,而且在更新前验证其有效性的代价相当高,因此我们无须在更新之前验证其有效性,而是结合事务的存储点机制,提供了数据完整性的保证。隔离级别的概念企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。由数据库理论可知,由于并发访问,在不可预料的时刻可能引发如下几个可以预料的问题:脏读:包含未提交数据的读取。例如,事务1更改了某行。事务2在事务1提交更改之前读取已更改的行。如果事务1回滚更改,则事务2便读取了逻辑上从未存在过的行。不可重复读取:当某个事务不止一次读取同一行,并且一个单独的事务在两次(或多次)读取之间修改该行时,因为在同一个事务内的多次读取之间修改了该行,所以每次读取都生成不同值,从而引发不一致问题。幻象:通过一个任务,在以前由另一个尚未提交其事务的任务读取的行的范围中插入新行或删除现有行。带有未提交事务的任务由于该范围中行数的更改而无法重复其原始读取。如你所想,这些情况发生的根本原因都是因为在并发访问的时候,没有一个机制避免交叉存取所造成的。而隔离级别的设置,正是为了避免这些情况的发生。事务准备接受不一致数据的级别称为隔离级别。隔离级别是一个事务必须与其它事务进行隔离的程度。较低的隔离级别可以增加并发,但代价是降低数据的正确性。相反,较高的隔离级别可以确保数据的正确性,但可能对并发产生负面影响。根据隔离级别的不同,DBMS为并行访问提供不同的互斥保证。在SQL Server数据库中,提供四种隔离级别:未提交读、提交读、可重复读、可串行读。这四种隔离级别可以不同程度地保证并发的数据完整性:隔离级别脏读不可重复读取幻像未提交读是是是提交读否是是可重复读否否是可串行读否否否可以看出,“可串行读”提供了最高级别的隔离,这时并发事务的执行结果将与串行执行的完全一致。如前所述,最高级别的隔离也就意味着最低程度的并发,因此,在此隔离级别下,数据库的服务效率事实上是比较低的。尽管可串行性对于事务确保数据库中的数据在所有时间内的正确性相当重要,然而许多事务并不总是要求完全的隔离。例如,多个作者工作于同一本书的不同章节。新章节可以在任意时候提交到项目中。但是,对于已经编辑过的章节,没有编辑人员的批准,作者不能对此章节进行任何更改。这样,尽管有未编辑的新章节,但编辑人员仍可以确保在任意时间该书籍项目的正确性。编辑人员可以查看以前编辑的章节以及最近提交的章节。这样,其它的几种隔离级别也有其存在的意义。在.net框架中,事务的隔离级别是由枚举System.Data.IsolationLevel所定义的:FlagsSerializablepublic enum IsolationLevel其成员及相应的含义如下:成员含义Chaos无法改写隔离级别更高的事务中的挂起的更改。ReadCommitted在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。ReadUncommitted可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。RepeatableRead在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。防止不可重复的读取,但是仍可以有幻像行。Serializable在DataSet上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。Unspecified正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。显而意见,数据库的四个隔离级别在这里都有映射。默认的情况下,SQL Server使用ReadCommitted(提交读)隔离级别。关于隔离级别的最后一点就是如果你在事务执行的过程中改变了隔离级别,那么后面的命名都在最新的隔离级别下执行隔离级别的改变是立即生效的。有了这一点,你可以在你的事务中更灵活地使用隔离级别从而达到更高的效率和并发安全性。最后的忠告无疑,引入事务处理是应对可能出现的数据错误的好方法,但是也应该看到事务处理需要付出的巨大代价用于存储点、回滚和并发控制所需要的CPU时间和存储空间。本文的内容只是针对Microsoft SQL Server数据库的,对应于.net框架中的System.Data.SqlClient命名空间,对于使用OleDb的情形,具体的实现稍有不同/ADO.NET事务处理分类:C#2012-03-02 00:14197人阅读评论(0)收藏举报数据库存储commandsybaseinsertexception一 事务处理介绍事务是这样一种机制,它确保多个SQL语句被当作单个工作单元来处理。事务具有以下的作用:* 一致性:同时进行的查询和更新彼此不会发生冲突,其他用户不会看到发生了变化但尚未提交的数据。* 可恢复性:一旦系统故障,数据库会自动地完全恢复未完成的事务。二 事务与一致性事务是完整性的单位,一个事务的执行是把数据库从一个一致的状态转换成另一个一致的状态。因此,如果事务孤立执行时是正确的,但如果多个事务并发交错地执行,就可能相互干扰,造成数据库状态的不一致。在多用户环境中,数据库必须避免同时进行的查询和更新发生冲突。这一点是很重要的,如果正在被处理的数据能够在该处理正在运行时被另一用户的修改所改变,那么该处理结果是不明确的。不加控制的并发存取会产生以下几种错误:1 丢失修改(lost updates)当多个事务并发修改一个数据时,不加控制会得出错误的结果,一个修改会覆盖掉另一个修改。2 读的不可重复性当多个事务按某种时间顺序存取若干数据时,如果对并发存取不加控制,也会产生错误。3 脏读(DIRDY DATA),读的不一致性4 光标带来的当前值的混乱事务在执行过程中它在某个表上的当前查找位置是由光标表示的。光标指向当前正处理的记录。当处理完该条记录后,则指向下一条记录。在多个事务并发执行时,某一事务的修改可能产生负作用,使与这些光标有关的事务出错。5 未释放修改造成连锁退出一个事务在进行修改操作的过程中可能会发生故障,这时需要将已做的修改回退(Rollback)。如果在已进行过或已发现错误尚未复原之前允许其它事务读已做过修改(脏读),则会导致连锁退出。6 一事务在对一表更新时,另外的事务却修改或删除此表的定义。数据库会为每个事务自动地设置适当级别的锁定。对于前面讲述的问题:脏读、未释放修改造成的连锁退出、一事务在对一表更新时另外的事务却修改或删除此表的定义,数据库都会自动解决。而另外的三个问题则需要在编程过程中人为地定义事务或加锁来解决。三 事务和恢复数据库本身肩负着管理事务的责任。事务是最小的逻辑工作单元,在这个工作单元中,对数据库的所有更新工作,要么必须全部成功,要么必须全部失败(回退)。只要应用程序指定了某段程序为一个事务并做了相应的处理(提交或回退),数据库系统会自动维护事务本身的特性。四 ORACLE数据库的事务定义ORACLE事务从COMMIT、ROLLBACK、连接到数据库或开始第一条可执行的SQL语句时开始,到一条COMMIT、ROLLBACK语句或退出数据库时结束。如果在一个事务中包含DDL语句,则在DDL语句的前后都会隐含地执行COMMIT语句,从而开始或结束一个事务。如果一个事务由于某些故障或者由于用户改变主意而必须在提交前取消它,则数据库被恢复到这些语句和过程执行之前的状态。利用ROLLBACK语句可以在COMMIT命令前随时撤消或回退一个事务。可以回退整个事务,也可以会退部分事务,但是不能回退一个已经被提交的事务。回退部分事务的ROLLBACK命令为:ROLLBACK to savepoint 存储点名存储点是用户放入事务中的标记,用来表示一个可被回退的位置。存储点通过在事务中放入一个SAVEPOINT命令而被插入。该命令的语法是:SAVEPOINT 存储点名如果在ROLLBACK语句中没有给出存储点名,则整个事务被回退。五 SYBASE数据库的事务定义SYBASE通过使用BEGIN TRANsaction和COMMIT TRANsaction命令指示SQL将任意数目的语句作为一个单元来处理。ROLLBACK TRANsaction命令则允许用户恢复到事务的开始,或恢复到事务内部已经被用SAVETRANsaction命令定义的存储点上。BEGIN TRANsaction和COMMIT TRANsaction能够包含任意数目的SQL语句和存储过程,方法很简单:BEGIN TRANsaction 事务名称COMMIT TRANsaction如果一个事务由于某些故障或者由于用户改变主意而必须在提交前取
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年高性能铁氧体磁体项目发展计划
- 干部廉洁考试及答案
- 2025年工信部考试中心题库及答案
- 房车知识培训班课件
- 2025年电工理论考试题目及答案
- 2025年广东军转考试真题及答案
- 2025年小学各科考试题及答案
- 慢丝车间安全培训课件
- 情景投稿课件模板
- 生物中考试题数学及答案
- 药包材生产质量管理手册
- 社会组织管理概论全套ppt课件(完整版)
- 政府预算理论与实务(第四版)全套教学课件
- 四年级上册美术课件第1课 送给老师的花|沪教版
- 轧机设备安装施工方案
- 最新开工报告范文
- (完整版)IATF16949新版过程乌龟图的编制与详解课件
- 制药企业仓库温湿度分布的验证
- GB∕T 3099.4-2021 紧固件术语 控制、检查、交付、接收和质量
- 山东临清实验中学2012学年八年级语文 7课背影共3课时教案(表格版) 人教新课标版
- 深圳牛津小学英语单词汇总
评论
0/150
提交评论