63在事务里对数据库修改进行封装.docx
- 文档编号:26678475
- 上传时间:2023-06-21
- 格式:DOCX
- 页数:22
- 大小:460.05KB
63在事务里对数据库修改进行封装.docx
《63在事务里对数据库修改进行封装.docx》由会员分享,可在线阅读,更多相关《63在事务里对数据库修改进行封装.docx(22页珍藏版)》请在冰豆网上搜索。
63在事务里对数据库修改进行封装
正如我们在第16章《概述添加、更新、删除数据》里探讨的那样,GridView控件内建的功能支持对每行数据的编辑和删除功能,你只需要稍稍动一下鼠标就可以创建丰富的数据修改界面而不用写一行代码.但是,在某些情况下,这还不够,我们需要让用户能够成批地处理数据.
比如,很多基于web(web-based)的电子邮件客户端,将所有邮件出来,每条邮件除了包含邮件信息(主题、发送者等)外,还包含一个checkbox控件。
这些界面允许用户同时删除多个邮件,用户只需要选中邮件,再点"删除所选邮件"按钮.当用户要编辑多条不同的记录的时候,提供一个批编辑界面是比较理想的.我们用不着让用户每次都选中一条要编辑的记录,再做相关的修改,最后点“更新”按钮,在批编辑界面里每条记录都有各自的编辑选项,用户可以快速地编辑多条记录再点“UpdateAll”按钮来保存对他们所做的修改.本系列我们将考察如何创建对数据进行添加、编辑、删除批处理的界面.
如果想对批处理执行atomicoperation(原子操作),那么首先,所做的操作要么都执行成功要么都失败,另外还要对数据访问层进行扩充以支持databasetransactions(数据库事务)。
数据库事务确保INSERT,UPDATE,和DELETE语句执行的atomicity(原子数)置于数据库事务的保护之下.另外,绝大多数的当代数据库系统都支持数据库事务.
在本系列我们先看如何扩充数据访问层以支持数据库事务,接下来我们看如何创建页面以包含添加、更新、删除数据的批处理界面,让我们开始吧.
注意:
在批处理事务里修改数据时,原子数(atomicity)并非总数必要的。
在批处理的某些情况下,某些修改成功某些修改失败是可以接受的。
比如删除电子邮件时,有些邮件在删除过程中发生了数据库错误,有些邮件没有发生错误,对这种没有发生错误的邮件,批处理照样将其删除掉.对这种情况,我们没有必要设置数据访问层DAL支持数据库事务.不过在其它某些情况下,原子数是至关重要的.比如某个客户想把资金从一个银行帐户转移到另一个银行帐号,下面2个操作必须执行成功:
首先,将第一个帐号的资金扣除,然后将资金转入第二个帐号.如果第一步执行成功,第二步执行失败,银行当然高兴,客户怕是要发疯了.在后面的文章里我们将创建添加、更新、删除的批处理界面,就算你不打算在这些页面里使用数据库事务,我也希望你照着本篇文章,对数据访问层进行扩展一支持数据库事务.
事务概述
绝大多数的数据库都支持事务,它可以将多个数据库命令当成一个逻辑单位进行处理.这些包含事务的命令要么都执行成功要么都执行失败.
一般来说,事务通过SQL命令来执行,使用如下的模式:
1.声明事务开始
2.执行构成事务的那些SQL命令
3.如果在第二步中的任何一个命令出错,执行事务回滚(rollbackthetransaction)
4.如果在第二步中的所有命令成功执行,提交事务
这些SQL命令可以通过手写的方式输入,比如写SQL脚本、创建存储过程、也可以通过编程的方式来构建,比如使用ADO.NET技术或调用System.Transactionsnamespace命名空间的类.在本文,我们仅仅考察用ADO.NET技术管理事务.在后面的教程我们看如何在数据访问层DataAccessLayer里使用存储过程,到那时,我们再来考察这些创建、回滚、提交事物的SQL命令。
另外,要获得更多信息请参考文章《ManagingTransactionsinSQLServerStoredProcedures》(
注意:
System.Transactionsnamespace命名空间的TransactionScopeclass类允许开发者通过编程的方式获取事务里的一系列命令,且允许事务包含多个数据源,甚至类型不同,比如:
MicrosoftSQLServerdatabase,或Oracledatabase,甚至Webservice.本教程我们使用ADO.NET技术而非TransactionScopeclass类,是因为ADO.NET指定数据库事务更详细,且在很多情况下占用资源更少.此外,在某些情况下,TransactionScopeclass类要用到MicrosoftDistributedTransactionCoordinator(MSDTC),围绕MSDTC的配置、执行和性能问题是比较专业、高级的问题稍微超出了本教程的范围.
在ADO.NET里,通过调用SqlConnectionclass类的BeginTransactionmethod方法启动事务,该方法返回一个SqlTransactionobject对象.将构成事务的数据操作命令放在try...catch区域,如果在try区域的某个命令出错的话,程序将转到catch区域,在此,通过SqlTransactionobject对象的Rollbackmethod方法执行事务回滚。
如果所有的命令执行成功,将调用位于try区域底部的SqlTransactionobject对象的Commitmethod方法来提交事务.下面的代码片段揭示了该模式。
要想看在ADO.NET里使用事务的更多例子,请参阅文章《MaintainingDatabaseConsistencywithTransactions》(
//CreatetheSqlTransactionobject
SqlTransactionmyTransaction=SqlConnectionObject.BeginTransaction();
try
{
/*
*...Performthedatabasetransaction’sdatamodificationstatements...
*/
//Ifwereachhere,noerrors,socommitthetransaction
myTransaction.Commit();
}
catch
{
//Ifwereachhere,therewasanerror,sorollbackthetransaction
myTransaction.Rollback();
throw;
}
默认情况下,强类型数据集(TypedDataSet)里的TableAdapters并不使用事务。
为此,我们要对TableAdapterclasses类进行扩展,以包含额外的方法以使用上述模式来执行事务。
在第二步,我们看如何使用一个partialclasses类来添加这些方法.
第一步:
创建批处理数据的页面
在我们考察如何扩展数据访问层DAL以支持数据库事务之前,让我们花点时间来创建一些ASP.NETweb页面,我们在本章及后面三章将用到它们.
添加一个名为BatchData的新文件夹,再添加如下的ASP.NET页面,务必套用Site.master模板页.
Default.aspx
Transactions.aspx
BatchUpdate.aspx
BatchDelete.aspx
BatchInsert.aspx
图1:
添加相关的页面
就像其它文件夹里的Default.aspx页面一样,用SectionLevelTutorialListing.ascx用户控件来列出本部分的章节。
将其从解决资源管理器里拖到Default.aspx页面.
图2:
将SectionLevelTutorialListing.ascx用户控件添加到Default.aspx页面
最后添加如下代码到Web.sitemap文件,具体的,将其添加到“CustomizingtheSiteMap”
url="~/BatchData/Default.aspx" description="Learnhowtoperformbatchoperationsasopposedto per-rowoperations."> url="~/BatchData/Transactions.aspx" description="SeehowtoextendtheDataAccessLayertosupport databasetransactions."/> url="~/BatchData/BatchUpdate.aspx" description="Buildabatchupdatinginterface,whereeachrowina GridViewiseditable."/> url="~/BatchData/BatchDelete.aspx" description="Explorehowtocreateaninterfaceforbatchdeleting byaddingaCheckBoxtoeachGridViewrow."/> url="~/BatchData/BatchInsert.aspx" description="Examinethestepsneededtocreateabatchinserting interface,wheremultiplerecordscanbecreatedatthe clickofabutton."/> 完成后,花几分钟在浏览器里登录页面,左面的菜单列出了本部分的各项 图3: SiteMap现在包含了本章节 第二步: 更新数据访问层以支持数据库事务 就像我们在第一章《CreatingaDataAccessLayer》探讨的一样,位于数据访问层的强类型数据集(TypedDataSet)由DataTables和TableAdapters构成. DataTables保存数据,而TableAdapters提供相应的方法从数据库读取数据,并根据DataTables的改动对数据库做相应的更新,等等.记得TableAdapters有2种更新数据的模式——BatchUpdate和DB-Direct.就BatchUpdate模式而言,TableAdapter可以传入DataSet,DataTable,或DataRows集,遍历这些数据对要添加、修改、删除的行执行相应的InsertCommand,UpdateCommand,orDeleteCommand方法。 就DB-Direct模式而言,TableAdapter传入的是那些需要进行添加、更新、删除操作的某条记录的列的值,再使用这些值执行相关的InsertCommand,UpdateCommand,或DeleteCommand命令. TableAdapter自动生成的方法并不使用事务.默认状态下,TableAdapter执行的每一个insert,update,或delete操作都看作是单独的、互不相干的.假定在业务逻辑层BLL里使用DB-Direct模式来向数据库添加十条记录,代码将分十次调用TableAdapter的Insert方法.如果前5条记录添加正常,而在添加第六条记录时发生异常,前5条记录仍然保存在数据库.同样的,用BatchUpdate模式来操作的话,效果亦然. 在某些情况下,我们想确保在进行一系列的改动时引入原子数(atomicity).为此,我们必须手动扩展TableAdapter,通过添加一些新的方法将InsertCommand,UpdateCommand,和DeleteCommands命令置于事务之下.在第一章《CreatingaDataAccessLayer》里,我们考察了使用部分类(partialclasses)对强类型数据集(TypedDataSet)里的DataTable的函数进行扩充.该技术同样适用于TableAdapter. 强类型数据集Northwind.xsd位于App_Code文件夹的DAL子文件夹里.在DAL文件夹里再创建一个名为TransactionSupport的子文件夹,再在里面添加一个新类,名为ProductsTableAdapter.TransactionSupport.cs(见图4).该类包含ProductsTableAdapter的使用事务的方法. 图4: 创建一个名为TransactionSupport的新文件夹并添加一个名为ProductsTableAdapter.TransactionSupport.cs的新类 在ProductsTableAdapter.TransactionSupport.cs文件里键入如下的代码: usingSystem; usingSystem.Data; usingSystem.Data.SqlClient; usingSystem.Configuration; usingSystem.Web; usingSystem.Web.Security; usingSystem.Web.UI; usingSystem.Web.UI.WebControls; usingSystem.Web.UI.WebControls.WebParts; usingSystem.Web.UI.HtmlControls; namespaceNorthwindTableAdapters { publicpartialclassProductsTableAdapter { privateSqlTransaction_transaction; privateSqlTransactionTransaction { get { returnthis._transaction; } set { this._transaction=value; } } publicvoidBeginTransaction() { //Opentheconnection,ifneeded if(this.Connection.State! =ConnectionState.Open) this.Connection.Open(); //CreatethetransactionandassignittotheTransactionproperty this.Transaction=this.Connection.BeginTransaction(); //AttachthetransactiontotheAdapters foreach(SqlCommandcommandinthis.CommandCollection) { command.Transaction=this.Transaction; } this.Adapter.InsertCommand.Transaction=this.Transaction; this.Adapter.UpdateCommand.Transaction=this.Transaction; this.Adapter.DeleteCommand.Transaction=this.Transaction; } publicvoidCommitTransaction() { //Committhetransaction this.Transaction.Commit(); //Closetheconnection this.Connection.Close(); } publicvoidRollbackTransaction() { //Rollbackthetransaction this.Transaction.Rollback(); //Closetheconnection this.Connection.Close(); } } } 类声明里的关键字partial向编译器表明代码里添加的成员(members)是添加到命名空间NorthwindTableAdapters里的ProductsTableAdapterclass类.我们注意到在文件的顶部有一个usingSystem.Data.SqlClient声明,这是因为TableAdapter被设置为使用SqlClientprovider,在其内部使用一个SqlDataAdapterobject对象来向数据库发出命令.因此,我们需要使用SqlTransactionclass类来启动事务,然后提交或回滚事务.如果没有使用MicrosoftSQLServer数据库的话,你需要调用恰当的provider. 这些方法被标记为public,我们可以在ProductsTableAdapter里,或数据访问层DAL的其它类,甚至是其它层比如业务逻辑层BLL来调用这些法. BeginTransaction()方法打开了TableAdapter的内部的SqlConnection(如果需要的话),开启事务并赋值给Transaction属性,并将事务分配(attache)给SqlDataAdapter的SqlCommandobjects对象.CommitTransaction()和RollbackTransaction()方法在关闭内部的Connectionobject对象前分别调用Transactionobject对象的Commit和Rollback方法. 添加上述代码后,我们将在ProductsDataTable或业务逻辑层BLL里添加方法以执行一系列的置于事务之下的命令.下面的代码在BatchUpdatepattern模式里使用一个事务来更新一个ProductsDataTableinstance实例.它调用BeginTransactionmethod方法来启动一个事务,然后用一个try...catch模块来发布数据更改命令.如果调用Adapterobject对象的Update方法出现异常,那么将转到catch区域,对事务进行回滚.记得执行BatchUpdatepattern模式的Update方法将遍历ProductsDataTable里的所有行(rows),执行相应的InsertCommand,UpdateCommand,和DeleteCommands命令.如果这些命令中的其中一个出现异常,事务将回滚,撤销在事务里的所做的更改.如果Update命令全部执行无异常,那么提交事务. publicintUpdateWithTransaction(Northwind.ProductsDataTabledataTable) { this.BeginTransaction(); try { //PerformtheupdateontheDataTable intreturnValue=this.Adapter.Update(dataTable); //Ifwereachhere,noerrors,socommitthetransaction this.CommitTransaction(); returnreturnValue; } catch { //Ifwereachhere,therewasanerror,sorollbackthetransaction this.RollbackTransaction(); throw; } } 将上述的UpdateWithTransaction()方法添加到文件ProductsTableAdapter.TransactionSupport.cs里的ProductsTableAdapterclass类。 另外,还可以将该方法添加到业务逻辑层的ProductsBLLclass类,不过要做些许修改: 即将this.BeginTransaction(),this.CommitTransaction(),andthis.RollbackTransaction()三中方法里的关键字“this”替换为“Adapter”(我们知道,ProductsBLL类里的ProductsTableAdapter的name属性即是Adapter). UpdateWithTransaction()方法使用的是BatchUpdate模式,不过也可在事务里调用DB-Direct模式,就像下面的代码显示的那样.DeleteProductsWithTrans
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 63 事务 数据库 修改 进行 封装