C#数据库事务原理及实践Word文档下载推荐.docx
- 文档编号:16314656
- 上传时间:2022-11-22
- 格式:DOCX
- 页数:15
- 大小:25.54KB
C#数据库事务原理及实践Word文档下载推荐.docx
《C#数据库事务原理及实践Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《C#数据库事务原理及实践Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
事务结束时,所有的内部数据结构(如B树索引或双向链表)都必须是正确的。
某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。
例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。
隔离性
由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
当事务可序列化时将获得最高的隔离级别。
在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。
由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。
持久性
事务完成之后,它对于系统的影响是永久性的。
该修改即使出现致命的系统故障也将一直保持。
DBMS的责任和我们的任务
企业级的数据库管理系统(DBMS)都有责任提供一种保证事务的物理完整性的机制。
就常用的SQLServer2000系统而言,它具备锁定设备隔离事务、记录设备保证事务持久性等机制。
因此,我们不必关心数据库事务的物理完整性,而应该关注在什么情况下使用数据库事务、事务对性能的影响,如何使用事务等等。
本文将涉及到在.net框架下使用C#语言操纵数据库事务的各个方面。
体验SQL语言的事务机制
作为大型的企业级数据库,SQLServer2000对事务提供了很好的支持。
我们可以使用SQL语句来定义、提交以及回滚一个事务。
如下所示的SQL代码定义了一个事务,并且命名为"
MyTransaction"
(限于篇幅,本文并不讨论如何编写SQL语言程序,请读者自行参考相关书籍):
DECLARE@TranNameVARCHAR(20)
SELECT@TranName=’MyTransaction’
BEGINTRANSACTION@TranNameGOUSEpubs
GO
UPDATEroysched
SETroyalty=royalty*1.10
WHEREtitle_idLIKE’Pc%’
COMMITTRANSACTIONMyTransaction
这里用到了SQLServer2000自带的示例数据库pubs,提交事务后,将为所有畅销计算机书籍支付的版税增加10%。
打开SQLServer2000的查询分析器,选择pubs数据库,然后运行这段程序,结果显而易见。
可是如何在C#程序中运行呢?
我们记得在普通的SQL查询中,一般需要把查询语句赋值给SalCommand.CommandText属性,这里也就像普通的SQL查询语句一样,将这些语句赋给SqlCommand.CommandText属性即可。
要注意的一点是,其中的"
GO"
语句标志着SQL批处理的结束,编写SQL脚本是需要的,但是在这里是不必要的。
我们可以编写如下的程序来验证这个想法:
//TranSql.csusingSystem;
usingSystem.Data;
usingSystem.Data.SqlClient;
namespaceAspcn
{
publicclassDbTranSql
{
file:
//将事务放到SQLServer中执行
publicvoidDoTran()
{
file:
//建立连接并打开
SqlConnectionmyConn=GetConn();
myConn.Open();
SqlCommandmyComm=newSqlCommand();
try
{
myComm.Connection=myConn;
myComm.CommandText="
DECLARE@TranNameVARCHAR(20)"
;
myComm.CommandText+="
SELECT@TranName=’MyTransaction’"
BEGINTRANSACTION@TranName"
USEpubs"
UPDATEroyschedSETroyalty=royalty*1.10WHEREtitle_idLIKE’Pc%’"
COMMITTRANSACTIONMyTransaction"
myComm.ExecuteNonQuery();
}
catch(Exceptionerr)
thrownewApplicationException("
事务操作出错,系统信息:
"
+err.Message);
finally
myConn.Close();
}
//获取数据连接
privateSqlConnectionGetConn()
stringstrSql="
DataSource=localhost;
IntegratedSecurity=SSPI;
userid=sa;
password="
SqlConnectionmyConn=newSqlConnection(strSql);
returnmyConn;
}
publicclassTest
publicstaticvoidMain()
DbTranSqltranTest=newDbTranSql();
tranTest.DoTran();
Console.WriteLine("
事务处理已经成功完成。
);
Console.ReadLine();
}
注意到其中的SqlCommand对象myComm,它的CommandText属性仅仅是前面SQL代码字符串连接起来即可,当然,其中的"
语句已经全部去掉了。
这个语句就像普通的查询一样,程序将SQL文本事实上提交给DBMS去处理了,然后接收返回的结果(如果有结果返回的话)。
很自然,我们最后看到了输出"
事务处理已经成功完成"
,再用企业管理器查看pubs数据库的roysched表,所有title_id字段以"
PC"
开头的书籍的royalty字段的值都增加了0.1倍。
这里,我们并没有使用ADO.net的事务处理机制,而是简单地将执行事务的SQL语句当作普通的查询来执行,因此,事实上该事务完全没有用到.net的相关特性。
了解.net中的事务机制
如你所知,在.net框架中主要有两个命名空间(namespace)用于应用程序同数据库系统的交互:
System.Data.SqlClient和System.Data.OleDb。
前者专门用于连接Microsoft公司自己的SQLServer数据库,而后者可以适应多种不同的数据库。
这两个命名空间中都包含有专门用于管理数据库事务的类,分别是System.Data.SqlClient.SqlTranscation类和System.Data.OleDb.OleDbTranscation类。
就像它们的名字一样,这两个类大部分功能是一样的,二者之间的主要差别在于它们的连接机制,前者提供一组直接调用SQLServer的对象,而后者使用本机OLEDB启用数据访问。
事实上,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.csusingSystem;
publicclassDbTran
//执行事务处理
myConn.Open();
SqlTransactionmyTran=newSqlTransaction();
myComm.Connection=myConn;
myComm.Transaction=myTran;
//定位到pubs数据库
USEpubs"
file:
//更新数据
//将所有的计算机类图书
UPDATEroyschedSETroyalty=royalty*1.10WHEREtitle_idLIKE’Pc%’"
//提交事务
myTran.Commit();
publicclassTest{publicstaticvoidMain()
DbTrantranTest=newDbTran();
tranTest.DoTran();
Console.WriteLine("
Console.ReadLine();
显然,这个程序非常简单,我们非常自信地编译它,但是,出乎意料的结果使我们的成就感顿时烟消云散:
errorCS1501:
重载"
SqlTransaction"
方法未获取"
0"
参数
是什么原因呢?
注意到我们初始化的代码:
SqlTransactionmyTran=newSqlTransaction();
显然,问题出在这里,事实上,SqlTransaction类并没有公共的构造函数,我们不能这样新建一个SqlTrancaction类型的变量。
在事务处理之前确实需要有一个SqlTransaction类型的变量,将该变量关联到SqlCommand类的Transcation属性也是必要的,但是初始化方法却比较特别一点。
在初始化SqlTransaction类时,你需要使用SqlConnection类的BeginTranscation()方法:
SqlTransactionmyTran;
myTran=myConn.BeginTransaction();
该方法返回一个SqlTransaction类型的变量。
在调用BeginTransaction()方法以后,所有基于该数据连接对象的SQL语句执行动作都将被认为是事务MyTran的一部分。
同时,你也可以在该方法的参数中指定事务隔离级别和事务名称,如:
myTran=myConn.BeginTransaction(IsolationLevel.ReadCommitted,"
SampleTransaction"
关于隔离级别的概念我们将在随后的内容中探讨,在这里我们只需牢记一个事务是如何被启动,并且关联到特定的数据链接的。
先不要急着去搞懂我们的事务都干了些什么,看到这一行:
myTran.Commit();
是的,这就是事务的提交方式。
该语句执行后,事务的所有数据库操作将生效,并且为数据库事务的持久性机制所保持--即使系统在这以后发生致命错误,该事务对数据库的影响也不会消失。
对上面的程序做了修改之后我们可以得到如下代码(为了节约篇幅,重复之处已省略,请参照前文):
//DoTran.cs……}
file:
publicvoidDoTran()
file:
SqlConnectionmyConn=GetConn();
myConn.Open();
SqlCommandmyComm=newSqlCommand();
//SqlTransactionmyTran=newSqlTransaction();
//注意,SqlTransaction类无公开的构造函数
SqlTransactionmyTran;
//创建一个事务
myTran=myConn.BeginTransaction();
try
//从此开始,基于该连接的数据操作都被认为是事务的一部分
//下面绑定连接和事务对象
myComm.Connection=myConn;
myComm.Transaction=myTran;
file:
//定位到pubs数据库
myComm.CommandText="
myComm.ExecuteNonQuery();
myTran.Commit();
catch(Exceptionerr)
thrownewApplicationException("
}
finally
myConn.Close();
……
到此为止,我们仅仅掌握了如何开始和提交事务。
下一步我们必须考虑的是在事务中可以干什么和不可以干什么。
C#数据库事务原理及实践(下)
另一个走向极端的错误
满怀信心的新手们可能为自己所掌握的部分知识陶醉不已,刚接触数据库库事务处理的准开发者们也一样,踌躇满志地准备将事务机制应用到他的数据处理程序的每一个模块每一条语句中去。
的确,事务机制看起来是如此的诱人——简洁、美妙而又实用,我当然想用它来避免一切可能出现的错误——我甚至想用事务把我的数据操作从头到尾包裹起来。
看着吧,下面我要从创建一个数据库开始:
usingSystem;
{
SqlTransactionmyTran;
myTran=myConn.BeginTransaction();
myComm.Connection=myConn;
myComm.Transaction=myTran;
//试图创建数据库TestDB
myComm.CommandText="
CREATEdatabaseTestDB"
myComm.ExecuteNonQuery();
myTran.Commit();
DbTrantranTest=newDbTran();
}
//---------------
未处理的异常:
System.Data.SqlClient.SqlException:
在多语句事务内不允许使用CREATEDATABASE语句。
atSystem.Data.SqlClient.SqlCommand.ExecuteNonQuery()
atAspcn.DbTran.DoTran()
atAspcn.Test.Main()
注意,如下的SQL语句不允许出现在事务中:
ALTERDATABASE
修改数据库
BACKUPLOG
备份日志
CREATEDATABASE
创建数据库
DISKINIT
创建数据库或事务日志设备
DROPDATABASE
删除数据库
DUMPTRANSACTION
转储事务日志
LOADDATABASE
装载数据库备份复本
LOADTRANSACTION
装载事务日志备份复本
RECONFIGURE
更新使用sp_configure系统存储过程更改的配置选项的当前配置(sp_configure结果集中的config_value列)值。
RESTOREDATABASE
还原使用BACKUP命令所作的数据库备份
RESTORELOG
还原使用BACKUP命令所作的日志备份
UPDATESTATISTICS
在指定的表或索引视图中,对一个或多个统计组(集合)有关键值分发的信息进行更新
除了这些语句以外,你可以在你的数据库事务中使用任何合法的SQL语句。
事务回滚
事务的四个特性之一是原子性,其含义是指对于特定操作序列组成的事务,要么全部完成,要么就一件也不做。
如果在事务处理的过程中,发生未知的不可预料的错误,如何保证事务的原子性呢?
当事务中止时,必须执行回滚操作,以便消除已经执行的操作对数据库的影响。
一般的情况下,在异常处理中使用回滚动作是比较好的想法。
前面,我们已经得到了一个更新数据库的程序,并且验证了它的正确性,稍微修改一下,可以得到:
//RollBack.cs
usingSystem
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 数据库 事务 原理 实践
![提示](https://static.bdocx.com/images/bang_tan.gif)