此外,您不必显式向事务登记资源。任何
创建事务范围
下面的示例说明 TransactionScope 类的简单用法。
Visual Basic
1Using scope As TransactionScope = New TransactionScope()
2
3 'Create and open the SQL connection. The work done on this connection will be a part of the transaction created by the TransactionScope
4 Dim myConnection As New SqlConnection("server=(local)\SQLExpress;Integrated Security=SSPI;database=northwind")
5 Dim myCommand As New SqlCommand()
6 myConnection.Open()
7 myCommand.Connection = myConnection
8
9 'Restore database to near it's original condition so sample will work correctly.
10 myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"
11 myCommand.ExecuteNonQuery()
12
13 'Insert the first record.
14 myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"
15 myCommand.ExecuteNonQuery()
16
17 'Insert the second record.
18 myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"
19 myCommand.ExecuteNonQuery()
20
21 myConnection.Close()
22
23 'Call complete on the TransactionScope or not based on input
24 Dim c As ConsoleKeyInfo
25 While (True)
26
27 Console.Write("Complete the transaction scope? [Y|N] ")
28 c = Console.ReadKey()
29 Console.WriteLine()
30 If (c.KeyChar = "Y") Or (c.KeyChar = "y") Then
31 scope.Complete()
32 Exit While
33 ElseIf ((c.KeyChar = "N") Or (c.KeyChar = "n")) Then
34 Exit While
35 End If
36 End While
37End Using
C#
1using (TransactionScope ts = new TransactionScope()){ //Create and open the SQL connection. The work done on this connection will be a part of the transaction created by the TransactionScope SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind"); SqlCommand myCommand = new SqlCommand(); myConnection.Open(); myCommand.Connection = myConnection; //Restore database to near it's original condition so sample will work correctly. myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"; myCommand.ExecuteNonQuery(); //Insert the first record. myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"; myCommand.ExecuteNonQuery(); //Insert the second record. myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"; myCommand.ExecuteNonQuery(); myConnection.Close(); //Call complete on the TransactionScope or not based on input ConsoleKeyInfo c; while (true) { Console.Write("Complete the transaction scope? [Y|N] "); c = Console.ReadKey(); Console.WriteLine(); if ((c.KeyChar == 'Y') || (c.KeyChar == 'y')) { // Commit the transaction ts.Complete(); break; } else if ((c.KeyChar == 'N') || (c.KeyChar == 'n')) { break; } }您创建了新的 TransactionScope 对象后,即开始事务范围。 如代码示例中所示,建议您使用 using 语句创建范围。C# 和 Visual Basic 中都提供 using 语句,其工作方式类似于 try...finally 块,可确保正确处理范围。
实例化 TransactionScope 时,事务管理器会确定要参与的事务。确定之后,该范围将始终参与此事务。这个决定基于两个因素:环境事务是否存在以及构造函数中 TransactionScopeOption 参数的值。环境事务是在其中执行代码的事务。您可以通过调用
完成事务范围
在您的应用程序完成了它要在某一事务中执行的所有工作后,应该只调用
如果调用此方法失败,则会中止该事务,因为事务管理器会将此解释为一个系统故障,或者与在事务范围内引发的异常等效的故障。但是,调用此方法并不确保将提交该事务。这只是一个向事务管理器通知您的状态的方法。在调用 Complete 方法后,您将无法再通过 Current 属性访问环境事务,这样做将会引发异常。
如果 TransactionScope 对象最初创建了该事务,则通过事务管理器提交该事务的实际工作将在 using 块中的最后一行代码后发生。如果它没有创建该事务,则只要
using 语句确保调用 TransactionScope 对象的
如果范围创建该事务,则引发
回滚事务
要回滚某个事务,不应在该事务范围内调用 Complete 方法。例如,您可以在该范围内引发异常。该异常所参与的事务将被回滚。
使用 TransactionScopeOption 管理事务流
通过在使用自己范围的方法内调用使用 TransactionScope 的方法,可以嵌套事务范围,下例中的 RootMethod
方法即如此。
2{
3 using(TransactionScope scope = new TransactionScope())
4 {
5 /* Perform transactional work here */
6 SomeMethod();
7 scope.Complete();
8 }
9}
10
11void SomeMethod()
12{
13 using(TransactionScope scope = new TransactionScope())
14 {
15 /* Perform transactional work here */
16 scope.Complete();
17 }
18}
19
最顶部的事务范围称作根范围。
TransactionScope 类提供若干重载构造函数,这些构造函数接受
TransactionScope 对象具有三个选择:
-
加入环境事务,或者在环境事务不存在时创建一个新的环境事务。
-
成为新的根范围;即,开始一个新事务,并使该事务成为自己范围内的新环境事务。
-
完全不参与事务。结果就是没有任何环境事务。
如果范围是用
如果范围是用
如果该范围是用
下表对上述选择加以总结。
TransactionScopeOption | 环境事务 | 该范围参与 |
---|---|---|
必需的 |
否 |
新事务(将成为根) |
要求新建 |
否 |
新事务(将成为根) |
抑制 |
否 |
无事务 |
必需的 |
是 |
环境事务 |
要求新建 |
是 |
新事务(将成为根) |
抑制 |
是 |
无事务 |
在 TransactionScope 对象连接现有环境事务时,处置范围对象可能不会结束该事务,除非范围中止该事务。如果该环境事务是由根范围创建,则只有在处置根范围时,才对该事务调用 Commit。如果该事务是手动创建的,则该事务的创建者中止或提交该事务后该事务结束。
下面的示例说明一个 TransactionScope 对象,该对象创建三个嵌套的范围对象,每个对象都用不同的 TransactionScopeOption 值实例化。
2//Default is Required
3{
4 using(TransactionScope scope2 = new
5 TransactionScope(TransactionScopeOption.Required))
6 {
7
8 }
9
10 using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew))
11 {
12
13 }
14
15 using(TransactionScope scope4 = new
16 TransactionScope(TransactionScopeOption.Suppress))
17 {
18
19 }
20}
21
该示例说明一个不具有任何环境事务的代码块,它使用 Required 创建新范围 (scope1
)。范围 scope1
是根范围,因为它创建一个新事务(事务 A)并使事务 A 成为环境事务。Scope1
然后再创建三个对象,每个对象都具有不同的 TransactionScopeOption 值。例如,scope2
是使用 Required 创建的,并且由于有一个环境事务,因此它连接 scope1
创建的第一个事务。请注意,scope3
是新事务的根范围,并且 scope4
不具有任何环境事务。
尽管 TransactionScopeOption 的默认值且最常用值是 Required,但其他每个值都各具不同用途。
如果您想要保留代码部分执行的操作,并且在操作失败的情况下不希望中止环境事务,则 Suppress 会对您很有帮助。例如,在您想要执行日志记录或审核操作时,或者在您想要向订户发布事件时(不管您的环境事务是提交还是中止),上述值就很有用。该值允许您在事务范围内具有非事务性的代码部分,如以下示例中所示。
2{
3 try
4 {
5 //Start of non-transactional section
6 using(TransactionScope scope2 = new
7 TransactionScope(TransactionScopeOption.Suppress))
8 {
9 //Do non-transactional work here
10 }
11 //Restores ambient transaction here
12 }
13 catch
14 {}
15 //Rest of scope1
16}
17
18
//注释:
事务的嵌套可以用在记录事务处理过程中的行为或者是在事务中,不管事务成功与否都需要执行的部分。-个人理解。^_^
事务的嵌套可以用在记录事务处理过程中的行为或者是在事务中,不管事务成功与否都需要执行的部分。-个人理解。^_^
在嵌套的范围内投票
尽管嵌套的范围可以加入根范围的环境事务,但在嵌套的范围内调用 Complete 对根范围没有任何影响。只有在从根范围一直向下到最后嵌套的范围中的所有范围都投票决定提交该事务时,才提交该事务。
设置 TransactionScope 超时
TransactionScope 的某些重载的构造函数接受
通常在两种情况下将 TransactionScope 超时设置为非默认值的其他值。第一种情况就是在开发期间,在您想要测试应用程序处理中止的事务的方式时。通过将该超时设置为一个较小的值(例如 1 微秒),可使您的事务失败,并可以因此观察您的错误处理代码。您将该值设置为小于默认超时的第二种情况是,在您认为该范围与导致死锁的资源争用有关时。在该情况中,您想要尽快中止该事务,不等待默认超时到期。
如果某一范围加入了环境事务,但指定了比环境事务所设置的超时值更短的超时值,则强制对 TransactionScope 对象采用新的、更短的超时,并且该范围必须在指定的嵌套时间内结束,否则将自动中止该事务。如果嵌套的范围的超时长于环境事务的超时,则不会有任何影响。
设置 TransactionScope 隔离级别
TransactionScope 的某些重载的构造函数接受
此外,并不是所有资源管理器都支持所有级别的隔离,并且它们可以选择参与比配置级别更高级别上的事务。
除 Serializable 之外,每一隔离级别也都可能遇到因访问相同信息的其他事务导致的不一致。不同隔离级别之间的差别体现在读取锁定和写入锁定的用法上。只有在事务访问资源管理器中的数据时才可能持有锁定,或者只有在提交或中止事务前才可能持有锁定。前者在通信量方面表现更好,而后者在一致性上表现更出色。这两种类型的锁定和两种类型的操作(读/写)提供了四个基本隔离级别。有关更多信息,请参见
在使用嵌套的 TransactionScope 对象时,必须配置所有嵌套的范围,以便精确使用同一隔离级别(如果它们要加入环境事务)。如果某一嵌套 TransactionScope 对象尝试加入环境事务,但它指定了不同的隔离级别,则会引发
与 COM+ 互操作
在您创建新 TransactionScope 实例时,可以在某一构造函数中使用