使用事务机制

google_chu 2004-01-06 11:15:16
事务是单独的工作单元。如果事务成功,在事务中所做的所有的数据修改都会在提交时完成并且永久地成为数据库的一部分。如果事务遇到错误,则必须取消或回滚,这样所有的数据修改都将被清除。
可以在ADO.NET中使用事务,以便确保数据库的一致性和完整性。
完成本节学习,你将能够:
 了解事务的重要性
 启动一个事务
 为事务指定适当的隔离级别
 提交或回滚事务
3.6.1 事务
事务是一组相关的任务,这些任务作为一个单元要么一起成功要么一起失败。用事务处理的术语来说,事务要么提交要么回滚。对于一个要提交的事务,所有的组成部分都必须保证对数据的任何更改都是永久性的。不论系统崩溃或是发生其它无法预料的事件,更改都必须是永久性的。
只要有一个部分不能达到此要求,整个事务就会失败。事务范围内所有对数据的改变都会回滚到某个特定的设置点。
对于使用事务的例子,考虑下面的情形:一个ASP.NET页面执行两个任务。首先,在数据库中创建了一个新表。然后,调用特定对象来收集数据、格式化数据以及向新表中插入数据。这两个任务是相关甚至是相互依赖的,在这种情形中,除非能向新表中填充数据,否则就要避免创建新表。在一个事务范围内执行两个任务会强制两者之间的联系。如果第二个任务失败,则第一个任务就会回滚到创建新表前的某个点。
(1) 本地事务和分布式事务
可以创建本地事务或分布式事务,描述如下:
 本地事务
本地事务被限制在某种单独的数据资源内,例如数据库或消息队列。这些数据资源通常提供本地事务功能。由于这些事务由数据资源本身来控制,所以管理起来轻松高效。
 分布式事务
事务还可以跨越多种数据资源。分布式事务使您可以去协调不同系统上特有的操作,从而使它们一起成功或者一起失败。
(2) ACID属性
术语ACID是指事务在应用程序中所起的作用。由事务处理的先驱们所创立的”ACID”,代表了原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持续性(Durability)。
这些属性确保可预知行为,强调了事务的“所有或没有”(all-or-none)的宗旨的作用;此宗旨的目的是在可变因素很多时能减少管理负担。
 原子性
事务是一个工作单元。在应用程序中,一系列包含在 BEGIN TRANSACTION 和 END TRANSACTION 语句之间的操作将在该工作单元中进行。事务只执行一次,且是不可分的,即要么完成全部工作要么不做任何工作。
 一致性
事务是一个完整的单元,因为它保持数据的一致性,它可以将数据从某种一致性状态转换到另一种一致性状态。
一致性需要能够保持被事务所绑定的数据。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序强制了所有已知的完整性约束。
 隔离性
事务是一个独立的单元。每个并行执行的事务看起来都应该像是系统中惟一的一个事务。
隔离性要求即使所有事务都在同时运行,每个事务也都应该像是惟一存在的一个事务那样去操作数据存储区。事务永远也看不到其他事务的中间阶段。
 持续性
如果事务成功,那么即使在提交后计算机立即崩溃,系统仍将保证对该事务的更新。专用的日志可以让系统重新启动程序来完成未完成的操作,以使事务可持续。

3.6.2 使用SQL语句管理事务
使用SQL语句可以在数据层管理事务。
(1) SQL事务语句
表 3 8描述了一些用于管理事务的SQL语句。可以在存储过程中使用这些语句,控制数据层中的事务行为。
表 3 8
事务语句 描述
BEGIN TRANS 标记事务的开始。所有在BEGIN TRANS语句后执行的语句被视为事务的一部分。
COMMIT TRANS 标记一个成功事务的结束,提交从BEGIN TRANS语句以后所做的所有更改。
ROLLBACK TRANS 将事务回滚到该事务的开始处。
 示例
下面的示例描述了如何使用Transact-SQL管理事务。本例删除了某个指定产品定单的详细信息,然后删除了产品本身。如果产生任何错误,为了保证一致性会回滚整个事务。
BEGIN TRANS
DECLARE @orderDetailsError int, @productError int
DELETE FROM "Order Details" WHERE ProductID=42
SELECT @orderDetailsError = @@ERROR
DELETE FROM Products WHERE ProductID=42
SELECT @productError = @@ERROR
IF @orderDetailsError = 0 AND @productError = 0
COMMIT TRANS
ELSE
ROLLBACK TRANS
3.6.3 使用ADO.NET管理事务
ADO.NET能够在中间层的.NET Framework应用程序中管理事务。可以选择在数据层中执行事务。
SqlConnection和 OleDbConnection对象包含一个BeginTransaction方法,它能够返回SqlTransaction 或OleDbTransaction对象。事务对象拥有Commit 和Rollback方法来管理应用程序中的事务。
(1) 执行事务
 通过使用ADO.NET执行事务
1) 调用连接对象的BeginTransaction 方法。将返回值赋给一个SqlTransaction(或OleDbTransaction)类型的变量。
2) 为要在事务中执行的所有命令对象设置Transaction属性来引用事务对象。
3) 执行必要的命令对象。
4) 如果命令圆满完成,则调用事务对象的Commit方法。如果发生任何问题,则调用Rollback回滚到初始条件。
 示例
下面的示例使用事务来协调Northwind数据库中的多个DELETE语句。第一个DELETE语句删除了”Order Details”表中ProductID 为42的所有条目,第二个DELETE语句删除了Products表中的ProductID 为42的产品。如果发生任何错误,事务将回滚并且所有删除操作都被取消。
' 打开数据库连接,开始一个事务。
' 在事务中执行两个删除语句。
' 适当地提交或回滚事务。

cnNorthwind.Open()

Dim trans As SqlTransaction = cnNorthwind.BeginTransaction()

Dim cmDel As New SqlCommand()
cmDel.Connection = cnNorthwind
cmDel.Transaction = trans

Try
cmDel.CommandText = _
"DELETE [Order Details] WHERE ProductID = 42"
cmDel.ExecuteNonQuery()
cmDel.CommandText = "DELETE Products WHERE ProductID = 42"
cmDel.ExecuteNonQuery()
trans.Commit()
Catch Xcp As Exception
trans.Rollback()
Finally
cnNorthwind.Close()
End Try
...全文
84 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
google_chu 2004-01-06
  • 打赏
  • 举报
回复
我看过了春节要是宽裕的话 我就直接去哈市。
google_chu 2004-01-06
  • 打赏
  • 举报
回复
就发这点吧
发多了恐怕不好
google_chu 2004-01-06
  • 打赏
  • 举报
回复



3.6.4 隔离级别
隔离级别为连接指定事务锁定行为。当多个事务访问同一数据时,选择适当的隔离级别可以防止由并发产生的问题。
 一种极端的做法是允许事务没有限制地访问数据库。这会使事务中对执行语句的等待时间最少,但会增加由于同步访问而损坏数据的危险。
 另一种极端的做法指定事务彼此之间完全隔离。事务会一个接着一个连续地执行。
事务的隔离级别控制一个事务所执行的工作是否影响或怎样去影响另一个事务所执行的工作。SQL Server使用“提交读”(read committed)作为它的默认隔离级别。在该隔离级别下,一旦在事务中修改记录,该记录就会被锁定。而简单的获取SELECT查询中的行的内容不会锁定该行。但是,如果使用“可重复读”(repeatable read)或“可串行读”(serializable)隔离级别,那么就会在SELECT查询中获取行时锁定该行。
一些数据库支持在查询中使用锁定提示。在SQL Server中,可以使用如下的查询方式来锁定一个事务中的数据行,而忽略事务的隔离级别。
SELECT CustomerID, CompanyName, ContactName, Phone FROM Customers
WITH (UPDLOCK) WHERE CustomerID = ’ALFKI’
查看数据库文档,找出它支持什么类型的事务隔离级别和锁定提示。
下面的代码片段通过使用OleDbTransaction对象和SELECT查询中的锁定提示在Microsoft SQL Server 2000 Desktop Engine (MSDE)数据库中对某一行进行悲观锁定。一旦代码获取查询的结果,该数据行就会在服务器端被锁定。可以在调用DataAdapter对象的Fill方法后设置一个断点来验证是否锁定了该数据。在程序运行到断点时,可以使用特别的查询工具(如SQL Server的查询分析器)检验该行的内容,但是任何试图修改该行内容的操作都会失败。
' Visual Basic .NET
Dim strConn, strSQL As String
strConn = “Provider=SQLOLEDB;Data Source=(local)\NetSDK;” & _
“Initial Catalog=Northwind;Trusted_Connection=Yes;"
strSQL = “SELECT CustomerID, CompanyName FROM Customers “ & _
“WITH (UPDLOCK) WHERE CustomerID = ’ALFKI’"
Dim cn As New OleDbConnection(strConn)
cn.Open()
Dim txn As OleDbTransaction = cn.BeginTransaction
Dim cmd As New OleDbCommand(strSQL, cn, txn)
Dim da As New OleDbDataAdapter(cmd)
Dim cb As New OleDbCommandBuilder(da)
Dim tbl As New DataTable()
da.Fill(tbl)
Dim row As DataRow = tbl.Rows(0)
row(“CompanyName”) = “Modified"
da.Update(tbl)
txn.Rollback()
cn.Close()

// Visual C# .NET
string strConn, strSQL;
strConn = “Provider=SQLOLEDB;Data Source=(local)\\NetSDK;” +
“Initial Catalog=Northwind;Trusted_Connection=Yes;";
strSQL = “SELECT CustomerID, CompanyName FROM Customers “ +
“WITH (UPDLOCK) WHERE CustomerID = ’ALFKI’";
OleDbConnection cn = new OleDbConnection(strConn);
cn.Open();
OleDbTransaction txn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand(strSQL, cn, txn);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
DataTable tbl = new DataTable();
da.Fill(tbl);
DataRow row = tbl.Rows[0];
row["CompanyName"] = “Modified";
da.Update(tbl);
txn.Rollback();
cn.Close();
(1) 并发问题示例
如果几个事务同时访问同一个数据,可能会发生下面的并发错误:
 读脏数据
读脏数据发生在当事务选择了某一数据行,而同时这行正在被另外一个事务更新。原来的事务读取了还没有提交的数据,并且该数据也许已经被其它事务修改了。
 不可重复读取
不可重复读取是指事务曾经读取过某个被提交的数据,而后该事务再次读取该数据时,得到了不同的值。在两次读操作之间其它事务更新了该数据就会发生非可重复读取的情况。
 幻象读取
幻象读取发生在当事务读取数据,而该数据同时正在被另外一个事务删除的情况中。如果原始事务再一次读取该数据,将不会得到已删除的行。

(2) 设置隔离级别的注意事项
SqlTransaction 和OleDbTransaction对象拥有名为IsolationLevel的属性。当调用连接对象的BeginTransaction方法时,可以设置该属性。
表 3 9按照升序列出了可用的隔离级别。在IsolationLevel 枚举中定义了这些值。
表 3 9
隔离级别 描述
ReadUncommitted 该事务隔离只能够防止在读取时破坏数据。
脏读、非可重复读取和幻象读取仍可能发生。
ReadCommitted 在读取数据时保持共享锁定以避免读取已修改的数据。但在事务结束前可以更改这些数据,这仍然可能导致非可重复读取或幻象读取。
这是默认的隔离级别。
RepeatableRead 锁定所有在查询中的数据。通过阻止其他用户对数据更新来防止非可重复读取。但是,幻象读取仍然可能发生。
Serializable 事务彼此之间完全独立。这将防止读脏数据、非可重复读取和幻象读取发生。
Unspecified 指定一个与正在使用的隔离级别不同的隔离级别,但却不能确定其级别。
 示例
下例描述了如何使用可序列化的隔离级别启动一个事务。以牺牲运行时性能为代价来最大限度地防止并发性错误的发生。
trans = cnNorthwind.BeginTransaction( _
IsolationLevel.Serializable)

7,765

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧