NET开发中的事务处理大比拼.doc_第1页
NET开发中的事务处理大比拼.doc_第2页
NET开发中的事务处理大比拼.doc_第3页
NET开发中的事务处理大比拼.doc_第4页
NET开发中的事务处理大比拼.doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

.NET开发中的事务处理大比拼 事务是一组组合成逻辑工作单元的数据库操作,在系统执行过程中可能会出错,但事务将控制和维护每个数据库的一致性和完整性。事务处理的主要特征是,任务要么全部完成,要么都不完成。在写入一些记录时,要么写入所有记录,要么什么都不写入。如果在写入一个记录时出现了一个失败,那么在事务处理中已写入的其他数据就会回滚。事务可能由很多单个任务构成。简单事务的一个常见例子:把钱从A账户转到B账户,这涉及两项任务,即从A账户把钱取出来;把钱存入B账户。两项任务要么同时成功,要么一起失败,给予回滚,以便保持账户的状态和原来相同。否则,在执行某一个操作的时候可能会因为停电、网络中断等原因而出现故障,所以有可能更新了一个表中的行,但没有更新相关表中的行。如果数据库支持事务,则可以将数据库操作组成一个事务,以防止因这些事件而使数据库出现不一致。事务的ACID属性如下。l 原子性(Atomicity):事务的所有操作是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。原子性消除了系统处理操作子集的可能性。l 一致性(Consistency):数据从一种正确状态转换到另一种正确状态。事务在完成时,必须使所有的数据都保持一致。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。当事务结束时,所有的内部数据结构都必须是正确的。在存款取款的例子中,逻辑规则是,钱是不能凭空产生或销毁的,对于每个(收支)条目必须有一个相应的抵衡条目产生,以保证账户是平的。l 隔离性(Isolation):由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。查看数据时数据所处的状态,要么是事务修改它之前的状态,要么是事务修改它之后的状态。简单的理解就是,防止多个并发更新彼此干扰。事务在操作数据时与其他事务操作隔离。隔离性一般是通过加锁的机制来实现的。l 持久性(Durability):事务完成之后,它对于系统的影响是永久性的。已提交的更改即使在发生故障时也依然存在。对于事务的开发,.NET平台也为我们提供了几种非常简单方便的事务机制。无论是在功能上还是性能上都提供了优秀的企业级事务支持。.NET开发者可以使用以下5种事务机制:l SQL和存储过程级别的事务。l ADO.NET级别的事务。l ASP.NET页面级别的事务。l 企业级服务COM+事务。l System.Transactions 事务处理。这5种事务机制有着各自的优势和劣势,分别表现在性能、代码数量和部署设置等方面。开发人员可以根据项目的实际情况选择相应的事务机制。下面就开始分别说明日常开发中5种事务的具体使用。1 .NET开发中的事务处理大比拼 之 SQL和存储过程级别事务2 .NET开发中的事务处理大比拼 之 ADO.NET级别的事务 3 .NET开发中的事务处理大比拼 之 ASP.NET页面级别的事务4 .NET开发中的事务处理大比拼 之 企业级服务COM+事务5 .NET开发中的事务处理大比拼 之 System.Transactions .NET开发中的事务处理大比拼 之 SQL和存储过程级别事务 数据库事务是其他事务模型的基础,当一个事务创建时不同数据库系统都有自己的规则。SQL Server默认在自动提交的模式下工作,每个语句执行完后都会立即提交;与此对照的是Oracle需要你包含一个提交语句。但是当一个语句通过OLE DB执行时,它执行完后一个提交动作会被附加上去。例如:DECLARE TranName VARCHAR(20);SELECT TranName = MyTransaction;BEGIN TRANSACTION TranName;GOUSE AdventureWorks;GODELETE FROM AdventureWorks.HumanResources.JobCandidate WHERE JobCandidateID = 13;GO COMMIT TRANSACTION MyTransaction;GO或者:CREATE PROCEDURE Tran1 as begin tran set xact_abort on Insert Into P_Category(CategoryId,Name)values(1,test1) Insert Into P_Category(CategoryId,Name)values(2,test2) commit tran GOset xact_abort on表示遇到错误立即回滚。当然你也可以这么写:CREATE PROCEDURE tran1 as begin tran Insert Into P_Category(CategoryId,Name)values(1,test1) if(error0) rollback tran else begin Insert Into P_Category(CategoryId,Name)values(2,test2) if(error0) rollback tran else commit tran end GO数据库级别事务有它的优势和限制。优势:l 所有的事务逻辑包含在一个单独的调用中。l 拥有运行一个事务的最佳性能。l 独立于应用程序。限制:l 事务上下文仅存在于数据库调用中。l 数据库代码与数据库系统有关。.NET开发中的事务处理大比拼 之 ADO.NET级别的事务 现在我们对事务的概念和原理都有所了解了,并且作为已经有一些基础的C#开发者,我们已经熟知编写数据库交互程序的一些要点,即:(1)使用SqlConnection类的对象的Open()方法建立与数据库服务器的连接。(2)然后将该连接赋给SqlCommand对象的Connection属性。(3)将欲执行的SQL语句赋给SqlCommand的CommandText属性。(4)通过SqlCommand对象进行数据库操作。创建一个ADO.NET事务是很简单的,需要定义一个SqlTransaction类型的对象。SqlConnection 和OleDbConnection对象都有一个 BeginTransaction 方法,它可以返回 SqlTransaction 或者OleDbTransaction 对象。然后赋给SqlCommand对象的Transcation属性,即实现了二者的关联。为了使事务处理可以成功完成,必须调用SqlTransaction对象的Commit()方法。如果有错误,则必须调用Rollback()方法撤销所有的操作。代码示例:基于以上认识,下面我们就开始动手写一个基于ADO.NET的事务处理程序。 (示例位置:光盘codech0504WebWebForm2)string conString = data source=;database=codematic;user id=sa;password=;SqlConnection myConnection = new SqlConnection(conString);myConnection.Open();/启动一个事务SqlTransaction myTrans = myConnection.BeginTransaction();/为事务创建一个命令SqlCommand myCommand = new SqlCommand();myCommand.Connection = myConnection;myCommand.Transaction = myTrans;try myCommand.CommandText = update P_Product set Name=电脑2 where Id=52; myCommand.ExecuteNonQuery(); myCommand.CommandText = update P_Product set Name=电脑3 where Id=53; myCommand.ExecuteNonQuery(); myTrans.Commit();/提交 Response.Write(两条数据更新成功);catch (Exception ex) myTrans.Rollback();/遇到错误,回滚 Response.Write(ex.ToString(); finally myConnection.Close();ADO.NET事务的优势和限制如下。优势:l 简单。l 和数据库事务差不多快。l 事务可以跨越多个数据库访问。l 独立于数据库,不同数据库的专有代码被隐藏了。限制:事务执行在数据库连接层上,所以需要在执行事务的过程中手动地维护一个连接。注 意所有命令都必须关联在同一个连接实例上,ADO.NET事务处理不支持跨多个连接的事务处理。.NET开发中的事务处理大比拼 之 ASP.NET页面级别的事务 ASP.NET事务可以说是在.NET平台上事务实现方式最简单的一种,你仅仅需要一行代码即可。在aspx的页面声明中加一个额外的属性,即事务属性Transaction=Required,它有如下的值:Disabled(默认)、NotSupported、Supported、Required和RequiresNew,这些设置和COM+及企业级服务中的设置一样,典型的一个例子是如果你想在页面上下文中运行事务,那么要将其设置为Required。如果页面中包含有用户控件,那么这些控件也会包含到事务中,事务会存在于页面的每个地方。 代码示例:页面声明Transaction=Required:页面引用:using System.EnterpriseServices;。然后,数据操作代码:protected void Button1_Click(object sender, EventArgs e) try Work1(); Work2(); ContextUtil.SetComplete();/提交事务 catch (System.Exception except) ContextUtil.SetAbort();/撤销事务 Response.Write(except.Message); private void Work1() string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); string strSql = Insert Into P_Category(CategoryId,Name)values(1,test1); SqlCommand myCommand = new SqlCommand(strSql, myConnection); myConnection.Open(); int rows = myCommand.ExecuteNonQuery(); myConnection.Close();private void Work2() string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); string strSql = Insert Into P_Category(CategoryId,Name)values(2,test2); SqlCommand myCommand = new SqlCommand(strSql, myConnection); myConnection.Open(); int rows = myCommand.ExecuteNonQuery(); myConnection.Close();ContextUtil是用于获取 COM+ 上下文信息的首选类。由于此类的成员全部为static,因此在使用其成员之前不需要对此类进行实例化。ASP.NET页面事务的优势和限制如下。l 优势:实现简单,不需要额外的编码。 l限制:页面的所有代码都是同一个事务,这样的事务可能会很大,而也许我们需要的是分开的、小的事务实现在Web层。.NET开发中的事务处理大比拼 之 企业级服务COM+事务 .NET Framework 依靠 MTS/COM+ 服务来支持自动事务处理。COM+ 使用 Microsoft Distributed Transaction Coordinator(DTC)作为事务管理器和事务协调器在分布式环境中运行事务。这样可使 .NET 应用程序运行跨多个资源结合不同操作(例如将定单插入SQL Server 数据库、将消息写入 Microsoft 消息队列(MSMQ)队列,以及从 Oracle 数据库检索数据)的事务。要实现COM+事务处理的类则必须继承System.EnterpriseServices.ServicedComponent,这些类需要是公共的,并且需要提供一个公共的默认的构造器。其实Web Service就是继承ServicedComponent,所以Web Service也支持COM+事务。要在类定义之前加属性Transaction(TransactionOption.Required)。类里面的每个方法都会运行在一个事务中。定义一个COM+事务处理的类:首先引用:using System.EnterpriseServices;。然后,继承ServicedComponent。Transaction(TransactionOption.Required)public class OrderData : ServicedComponentTransactionOption枚举类型支持5个值:Disabled、NotSupported、Required、RequiresNew和Supported,如表5-3所示。表5-3 TransactionOption枚举类型支持5个值值说 明Disabled忽略当前上下文中的任何事务NotSupported使用非受控事务在上下文中创建组件Required如果事务存在则共享事务,并且如有必要则创建新事务RequiresNew使用新事务创建组件,而与当前上下文的状态无关Supported如果事务存在,则共享该事务一般来说COM+中的组件需要Required 或Supported。当组件用于记录或查账时RequiresNew 很有用,因为组件应该与活动中其他事务处理的提交或回滚隔离开来。派生类可以重载基类的任意属性。如OrderData选用Required,派生类仍然可以重载并指定RequiresNew或其他值。 COM+事务有手动处理和自动处理两种方式,自动处理就是在所需要自动处理的方法前加上AutoComplete,根据方法的正常或抛出异常决定提交或回滚。手动处理就是调用ContextUtil类中的EnableCommit、SetComplete和SetAbort方法。实现步骤如下。1给程序添加强名1)创建一对密钥 用来创建密钥的工具是称为sn.exe的共享工具。通常通过命令提示运行它,该工具可执行各种任务以生成并提取密钥。我们需要用以下方式来运行sn.exe。 sn k c:key.snk 其中key.snk 代表将保存密钥的文件的名称。它的名称可以是任意的,不过习惯上带有.snk后缀名。 2)签名 这个文件必须在AssemblyKeyFile属性中引用,签名通常是在编译时进行的。签名时,用户可利用C属性通知编译器应该使用正确的密钥文件对DLL进行签名。要做到这一点用户需要打开工程中的AssemblyInfo.cs文件并进行修改。 assembly:AssemblyKeyFile(“.key.snk”) 注 意key.snk文件和项目文件在同一个文件夹内。2手动事务处理创建一个项目用以实现事务处理的业务类ClassTran。代码示例: (示例位置:光盘codech0504ClassTranOrderData1) using System;using System.Data.SqlClient;using System.EnterpriseServices; /企业级服务COM+事务namespace ClassTran Transaction(TransactionOption.Required) public class OrderData1 : ServicedComponent /手动事务 public string WorkTran() try ContextUtil.EnableCommit(); Work1(); Work2(); ContextUtil.SetComplete(); return 成功!; catch (Exception ex) ContextUtil.SetAbort(); return 失败!; private void Work1() string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); string strSql = Insert Into P_Category(CategoryId,Name)values(1,test1); SqlCommand myCommand = new SqlCommand(strSql, myConnection); myConnection.Open(); int rows = myCommand.ExecuteNonQuery(); myConnection.Close(); private void Work2() string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); string strSql = Insert Into P_Category(CategoryId,Name)values(2,test2); SqlCommand myCommand = new SqlCommand(strSql, myConnection); myConnection.Open(); int rows = myCommand.ExecuteNonQuery(); myConnection.Close(); 3自动事务处理代码示例:在方法之前增加属性AutoComplete(true),这样如果方法执行时没有异常就默认提交,如果有异常则这个方法就会回滚。 (示例位置:光盘codech0504ClassTranOrderData2)using System;using System.Data.SqlClient;using System.EnterpriseServices;/企业级服务COM+事务namespace ClassTran Transaction(TransactionOption.Required) public class OrderData2 : ServicedComponent /自动事务 AutoComplete(true) public string WorkTran() string msg = ; string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); myConnection.Open(); SqlCommand myCommand = new SqlCommand(); myCommand.Connection = myConnection; try myCommand.CommandText = update P_Product set Name=电脑2 where Id=52; myCommand.ExecuteNonQuery(); myCommand.CommandText = update P_Product set Name=电脑3 where Id=53; myCommand.ExecuteNonQuery(); msg =成功!; catch (Exception ex) msg = 失败:+ex.Message; finally myConnection.Close(); return msg; 4事务方法调用代码示例: (示例位置:光盘codech0504WebWebForm4.aspx)protected void Button1_Click(object sender, EventArgs e) ClassTran.OrderData1 od1 = new ClassTran.OrderData1(); od1.WorkTran();protected void Button2_Click(object sender, EventArgs e) ClassTran.OrderData2 od2 = new ClassTran.OrderData2(); od2.WorkTran();在需要事务跨 MSMQ 和其他可识别事务的资源(例如SQL Server 数据库)运行的系统中,只能使用 DTC 或 COM+ 事务,除此之外没有其他选择。DTC 协调参与分布式事务的所有资源管理器,也管理与事务相关的操作。企业级服务COM+事务的前提及优缺点如下。前提:l 需要强名字。l 使用事务的对象需要继承ServicedComponent。优势:l 执行分布式事务,多个对象可以轻松地运行在同一个事务处理中,事务处理还可以自动登记。l 获得COM+服务,诸如对象构建和对象池等。缺点:l 由于存在 DTC 和 COM 互操作性开销,导致性能降低。l COM+ 1.0要求每个事务的隔离级别都设置为Serializable。l 使用Enterprise Services的事务总是线程安全的, 也就是说你无法让多个线程参与到同一个事务中。.NET开发中的事务处理大比拼 之 System.Transactions 在 .NET Framework 2.0中增加了System.Transactions,这是一种新的命名空间,完全专注于控制事务性行为。引入了执行事务性工作的更简单方法及一些新的性能优化。System.Transactions提供了一个“轻量级”的、易于使用的Transaction框架。在上节中,要实现Transaction需要利用EnterpriseServices,让组件从ServiceComponent继承下来。而通过System.Transactions,则只要简单的几行代码,不需要继承,不需要Attribute标记。用户根本不需要考虑是简单事务还是分布式事务。新模型会自动根据事务中涉及的对象资源判断使用何种事务管理器。简而言之,对于任何的事务,用户只要使用同一种方法进行处理即可。下面介绍System.Transactions的几种用法。首先要引用:using System.Transactions;。其次,将事务操作代码放在TransactionScope中执行。如: using (TransactionScope ts = new TransactionScope() /事务操作代码 ts.Complete();代码示例:这是最简单,也是最常见的用法。创建了新的 TransactionScope 对象后,即开始创建事务范围。如代码示例所示,建议使用 using 语句创建范围。位于 using 块内的所有操作将成为一个事务的一部分,因为它们共享其所定义的事务执行上下文。本例中的最后一行,调用 TransactionScope 的 Complete 方法,将导致退出该块时请求提交该事务。此方法还提供了内置的错误处理,出现异常时会终止事务。 (示例位置:光盘codech0504ClassTranOrderData3)using (TransactionScope ts = new TransactionScope()/使整个代码块成为事务性代码 #region 在这里编写需要具备Transaction的代码 string msg = ; string conString = data source=;database=codematic;user id=sa;password=; SqlConnection myConnection = new SqlConnection(conString); myConnection.Open(); SqlCommand myCommand = new SqlCommand(); myCommand.Connection = myConnection; try myCommand.CommandText = update P_Product set Name=电脑2 where Id=52; myCommand.ExecuteNonQuery(); myCommand.CommandText = update P_Product set Name=电脑3 where Id=53; myCommand.ExecuteNonQuery(); msg = 成功!; catch (Exception ex) msg = 失败: + ex.Message; finally myConnection.Close(); #endregion ts.Complete(); return msg; 上面的代码演示了在一个Transaction Scope里面打开一个数据库连接的过程。这个数据库连接由于处在一个Transaction Scope里面,所以会自动获得Transaction的能力。如果这里数据库连接的是SQL Server 2005,那么这个Transaction将不会激活一个MSDTC管理的分布式事务,而是会由.NET创建一个Local Transaction,性能非常高。但是如果是SQL Server 2000,则会自动激活一个分布式事务,在性能上会受一定的损失。再看下面的例子:void MethodMoreConn() using (TransactionScope ts = new TransactionScope() using (SqlConnection conn = new SqlConnection(conString1) conn.Open(); using (SqlConnection conn2 = new SqlConnection(conString2) conn2.Open(); ts.Complete(); 这个例子更加充分地说明了Transaction Scope的强大,两个数据库连接!虽然上面的conn和conn2是两个不同的连接对象,可能分别连接到不同的数据库,但是由于它们处在一个TransactionScope中,它们就具备了“联动”的Transaction能力。在这里,将自动激活一个MSDTC管理的分布式事务(可以通过打开【管理工具】里面的组件服务,来查看当前的分布式事务列表)。1在分布式事务中登记ADO.NET 2.0 中的新增功能支持使用 EnlistTransaction 方法在分布式事务中登记。由于 EnlistTransaction 在 Transaction 实例中登记连接,因此,该方法利用 System.Transactions 命名空间中的可用功能来管理分布式事务,从而比使用 System.EnterpriseServices. ITransaction 对象的 EnlistDistributedTransaction 更可取。此外,其语义也稍有不同:在一个事务中显式登记了某个连接后,如果第一个事务尚未完成,则无法取消登记或在另一个事务中登记该连接。void MethodEnlist() CommittableTransaction tx = new CommittableTransaction(); using (

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论