当应用程序需要在多个数据库中进行事务性操作的时候,使用TransactionScope类可以方便地实现应用程序的这一需求。只要对多个数据库的操作代码位于同一个事务范围内,即可实现多数据库连接的事务操作。
技术要点
本示例主要说明了如何在程序中使用TransactionScope实现多数据库连接事务操作,技术要点如下。
— 因为位于同一个事务范围内的不同的数据库操作,程序视为同一个事务,所以使用事务范围能够简便地实现多数据连接的事务操作。
— 在事务范围内应调用且仅仅调用一次Complete方法,当事务范围的Complete方法调用时,事务范围中的数据操作尝试提交,提交失败时自动回滚,如果在事务范围内未执行Complete方法,则导致事务范围在操作未提交的情况下结束。
实现步骤
(1)创建控制台应用程序项目,命名为“MultiDatabaseTransactionScope”。
(2)打开并编辑Program.cs文件,代码如下所示。
using System;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using System.Data;
using System.Data.SqlClient;
namespace MultiDatabaseTransactionScope
{
class Program
{
static void Main(string[] args)
{
//在创建的事务范围实例内运行代码
using (TransactionScope ts = new TransactionScope())
{
//连接数据库1的字符串
string ConnectionString1 = @"Data Source = localhost; Initial Catalog = Northwind; Integrated Security = SSPI;";
//创建数据库1连接类实例1
SqlConnection conn1 = new SqlConnection(ConnectionString1);
//创建数据库1命令类实例1
SqlCommand command1 = new SqlCommand(@"INSERT Shippers(CompanyName,Phone)
VALUES('Test Ship2','0000-0002')", conn1);
conn1.Open();//连接数据库1
command1.ExecuteNonQuery();//在数据库1上执行命令
Console.WriteLine("数据库1的命令已执行");
conn1.Close();//关闭数据库1
//连接数据库2的字符串
string ConnectionString2 = @"Data Source = localhost; Initial Catalog = pubs; Integrated Security = SSPI;";
//创建数据库2连接类实例2
SqlConnection conn2 = new SqlConnection(ConnectionString2);
//创建数据库2命令类实例2
SqlCommand command2 = new SqlCommand(@"INSERT Discounts(Discounttype,Discount) VALUES('Other',12)", conn2);
conn2.Open();//连接数据库2
command2.ExecuteNonQuery();//在数据库2上执行命令
Console.WriteLine("数据库2的命令已执行");
conn2.Close();//关闭数据库2
Console.Write("是否提交事务?(Y/N)");
if (Console.ReadKey(false).Key == ConsoleKey.Y)
{
ts.Complete();//提交事务
Console.WriteLine("");
Console.WriteLine("事务提交完成");
}
else
{
Console.WriteLine("取消事务提交");
}
}
}
}
}
(3)按F5键运行程序,运行结果如下所示。
数据库1的命令已执行
数据库2的命令已执行
是否提交事务?(Y/N)y
事务提交完成
使用2.0的新事务方式也有快一年了,刚开始时候遇到的一些使用疑点问题都在现在的项目中遇到,并解决,现在做一下总结:
一、 在TransactionScope中,如果不是必须要避免它启用DTC分布式事务,因为性能低下;而对于TransactionScope来说它是以连 接对象Connection做为识别单位的,也就是说即便是相同连接字符串ConnectionString的两个连接对象Connection在 TransactionScope也是会启用DTC分布式事务的,避免的方法就是在一个TransactionScope中使用一个唯一的连接对象 Connection。
二、在TransactionScope中默认的事务级别是Serializable,即在 事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需 要修改默认的事务级别:
option.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, option))
所有的事务级别如下:
成员名称 说明
Chaos 无法改写隔离级别更高的事务中的挂起的更改。
ReadCommitted 不可以在事务期间读取可变数据,但是可以修改它。
ReadUncommitted 可以在事务期间读取和修改可变数据。
RepeatableRead 可以在事务期间读取可变数据,但是不可以修改。可以在事务期间添加新数据。
Serializable 可以在事务期间读取可变数据,但是不可以修改,也不可以添加任何新数据。
Snapshot 可以读取可变数据。在事务修改数据之前,它验证在它最初读取数据之后另一个事务是否更改过这些数据。如果数据已被更新,则会引发错误。这样使事务可获取先前提交的数据值。
在 尝试提升以此隔离级别创建的事务时,将引发一个 InvalidOperationException,并产生错误信息 “Transactions with IsolationLevel Snapshot cannot be promoted”(无法提升具 有 IsolationLevel 快照的事务)。
Unspecified 正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。如果设置了此值,则会引发异常。
使用TransactionScopeOption实现事务选项控制
TransactionScopeOption枚举是创建事务范围的重要选项,该枚举中包含三个成员,其中Required成员表示创建的范围需要 一个事务,如果已经存在外部的事务,就使用外部事务作为当前的事务,如果不存在外部事务,就创建一个新的事务,在事务范围的构造函数中,如果没有指定 TransactionScopeOption枚举的参数,默认使用Required创建事务范围。RequiresNew成员表示为当前范围创建一个新 的事务,而无论是否存在外部事务。Suppress成员表示取消当前范围的外部事务,范围内的所有操作在事务外部执行。
技术要点
本示例主要说明了如何在程序中使用TransactionScopeOption实现事务选项控制,技术要点如下。
使用RequiresNew成员创建的事务范围时,即使存在外部事务,当前范围也将创建新的事务,这样当前事务范围在调用Complete方法结束事务范围的时候,就执行了提交动作,而不是等到外部事务调用Complete方法时才进行提交。
使用Required成员创建的事务范围时,如果存在外部事务,就使用外部事务,这样当前事务范围在调用Complete方法结束事务范围的时候,实际上并不能进行执行提交动作。只有当外部的事务范围调用Complete方法结束时,才能执行提交动作。
实现步骤
(1)创建控制台应用程序项目,命名为“ControlTransactionScopeOption”。
(2)打开并编辑Program.cs文件,代码如下所示。
using System; |
(3)按F5键运行程序,运行结果如下所示。
1 Speedy Express (503) 555-9831 |
源程序解读
(1)本示例程序定义了一个外部的事务范围ts1,在该范围内分别使用TransactionScopeOption枚举的RequiresNew 成员和Required成员创建了两个事务范围。在这两个事务范围内,分别创建数据库连接,并执行SQL命令语句。然后在事务范围之外,查询并显示数据库 中的表记录,以检查事务的提交情况。本示例程序的流程图如图13.2所示。
图13.2 使用TransactionScopeOption实现事务选项控制的示例程序流程图 |
(2)根据程序运行结果显示,使用Required成员创建的事务范围中的操作未被提交,原因是Required成员创建的事务范围使用的是外部事务,在外部事务未提交时当前事务范围中的所有数据操作均未提交。
(3)除去本示例程序注释的外部事务范围ts1的调用Complete方法语句,将结束ts1事务,并将该事务范围内的所有数据操作提交,此时将提交Required成员创建的事务范围内的数据操作。
对MSDTC组件设置:
步骤:
在控制面板--->管理工具--->服务 中,开启Distributed Transaction Coordinator 服务。
a.控制面板->管理工具->组件服务->计算机->我的电脑->右键->属性
b.选择MSDTC页, 确认"使用本地协调器"
c.点击下方"安全配置"按钮
d.勾选: "允许网络DTC访问","允许远程客户端","允许入站","允许出站","不要求进行身份验证".
e.对于数据库服务器端, 可选择"要求对呼叫方验证"
f.勾选:"启用事务Internet协议(TIP)事务"。
g.在双方防火墙中增加MSDTC.exe例外
可用命令行: netsh firewall set allowedprogram %windir%\system32\msdtc.exe MSDTC enable
4、重启IIS服务器。