使用 System.Transactions
适用范围:SQL Server
System.Transactions 命名空间提供与 ADO.NET 和 SQL Server 公共语言运行时 (CLR) 集成完全集成的事务框架。 System.Transactions.TransactionScope 类通过在分布式事务中隐式登记连接,使代码块事务化。 必须在由 TransactionScope 标记的代码块末尾调用 Complete 方法。 当程序执行离开代码块时,将调用 Dispose 方法,导致未调用 Complete 方法时停止事务。 如果已引发导致代码离开范围的异常,则将该事务视为停止使用。
建议使用 using 块来确保退出 using 块时对 TransactionScope 对象调用 Dispose 方法。 无法提交或回滚挂起的事务可能会严重降低性能,因为 TransactionScope 的默认超时为 1 分钟。 如果不使用 using 语句,则必须在 Try 块中执行所有工作,并在 Finally 块中显式调用 Dispose 方法。
如果在 TransactionScope 中发生异常,则事务将标记为不一致且被放弃。 释放 TransactionScope 时,会回滚它。 如果未发生异常,则提交参与的事务。
仅当访问本地和远程数据源或外部资源管理器时,才应使用 TransactionScope 。 这是因为 TransactionScope 始终会导致事务升级,即使仅在上下文连接内使用事务也是如此。
注意
TransactionScope 类默认使用 Serializable 的 System.Transactions.Transaction.IsolationLevel 创建事务。 根据您的应用程序,您可能希望考虑降低隔离级别,以避免在应用程序中发生争用激烈的情况。
注意
建议您在分布式事务内针对远程服务器仅执行更新、插入和删除操作,因为这些操作占用大量数据库资源。 如果将在本地服务器上执行该操作,则不需要分布式事务,而使用本地事务。 SELECT 语句可能会不必要地锁定数据库资源,在某些情况下,可能必须使用事务进行选择。 应在事务范围之外执行任何非数据库工作,除非它涉及其他事务资源管理器。 尽管事务范围内的异常会阻止事务提交,但 TransactionScope 类没有针对回滚代码在事务本身范围之外所做的任何更改的预配。 如果需要在回滚事务时执行一些操作,则必须编写自己的 System.Transactions.IEnlistmentNotification 接口实现,并在事务中显式登记。
示例
若要使用 System.Transactions,必须具有对 System.Transactions.dll 文件的引用。
以下代码演示如何创建可针对两个不同的 SQL Server 实例升级的事务。 这些实例由两个不同的 System.Data.SqlClient.SqlConnection 对象表示,这些对象包装在 TransactionScope 块中。 该代码使用 using 语句创建 TransactionScope 块,并打开第一个连接,该连接会自动在 TransactionScope 中登记。 该事务最初作为轻型事务登记,而不是完全分布式事务。 代码假定存在条件逻辑(为简洁起见,已省略该逻辑)。 仅当需要时,它才会打开第二个连接,将其登记在 TransactionScope 中。 打开该连接后,事务将自动提升为完全分布式事务。 然后,代码调用 TransactionScope.Complete,该事务提交。 代码在退出 连接的 using 语句时释放两个连接。 TransactionScope 的 TransactionScope.Dispose 方法在 TransactionScope 的使用块终止时自动调用。 如果在 TransactionScope 块中的任何时间点引发异常,则不会调用 Complete,分布式事务将在释放 TransactionScope 时回滚。
Visual Basic
Using transScope As New TransactionScope()
Using connection1 As New SqlConnection(connectString1)
' Opening connection1 automatically enlists it in the
' TransactionScope as a lightweight transaction.
connection1.Open()
' Do work in the first connection.
' Assumes conditional logic in place where the second
' connection will only be opened as needed.
Using connection2 As New SqlConnection(connectString2)
' Open the second connection, which enlists the
' second connection and promotes the transaction to
' a full distributed transaction.
connection2.Open()
' Do work in the second connection.
End Using
End Using
' Commit the transaction.
transScope.Complete()
End Using
C#
using (TransactionScope transScope = new TransactionScope())
{
using (SqlConnection connection1 = new
SqlConnection(connectString1))
{
// Opening connection1 automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Do work in the first connection.
// Assumes conditional logic in place where the second
// connection will only be opened as needed.
using (SqlConnection connection2 = new
SqlConnection(connectString2))
{
// Open the second connection, which enlists the
// second connection and promotes the transaction to
// a full distributed transaction.
connection2.Open();
// Do work in the second connection.
}
}
// The Complete method commits the transaction.
transScope.Complete();
}