使用TransactionScope实现单数据库连接事务操作
2009-03-12 08:23
666 查看
当应用程序需要在多个数据库中进行事务性操作的时候,使用TransactionScope类可以方便地实现应用程序的这一需求。只要对多个数据库的操作代码位于同一个事务范围内,即可实现多数据库连接的事务操作。
— 因为位于同一个事务范围内的不同的数据库操作,程序视为同一个事务,所以使用事务范围能够简便地实现多数据连接的事务操作。
— 在事务范围内应调用且仅仅调用一次Complete方法,当事务范围的Complete方法调用时,事务范围中的数据操作尝试提交,提交失败时自动回滚,如果在事务范围内未执行Complete方法,则导致事务范围在操作未提交的情况下结束。
(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,即在 事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需 要修改默认的事务级别:
TransactionOptions option = new TransactionOptions();
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文件,代码如下所示。
(3)按F5键运行程序,运行结果如下所示。
源程序解读
(1)本示例程序定义了一个外部的事务范围ts1,在该范围内分别使用TransactionScopeOption枚举的RequiresNew 成员和Required成员创建了两个事务范围。在这两个事务范围内,分别创建数据库连接,并执行SQL命令语句。然后在事务范围之外,查询并显示数据库 中的表记录,以检查事务的提交情况。本示例程序的流程图如图13.2所示。
(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服务器。
技术要点
本示例主要说明了如何在程序中使用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,即在 事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需 要修改默认的事务级别:
TransactionOptions option = new TransactionOptions();
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; using System.Collections.Generic; using System.Text; using System.Data; using System.Data.SqlClient; using System.Transactions; namespace ControlTransactionScopeOption { class Program { static void Main(string[] args) { //使用事务范围ts1 using (TransactionScope ts1 = new TransactionScope()) { //连接数据库的字符串1 string ConnectionString1 = @"Data Source = localhost; Initial Catalog = Northwind; Integrated Security = SSPI;"; //使用RequiresNew参数创建ts1的子事务subts1 using (TransactionScope subts1 = new TransactionScope (TransactionScopeOption.RequiresNew)) { //创建数据库连接类实例1 SqlConnection conn1 = new SqlConnection(ConnectionString1); //将在数据库连接实例1上执行的命令 SqlCommand command1 = new SqlCommand(@"INSERT Shippers (CompanyName, Phone) VALUES('Test Ship1','0000-0001')", conn1); conn1.Open(); command1.ExecuteNonQuery();//执行数据库操作 conn1.Close(); subts1.Complete();//完成子事务1 } //连接数据库的字符串2 string ConnectionString2 = @"Data Source = localhost; Initial Catalog = Northwind; Integrated Security = SSPI;"; //使用Required参数创建ts1的子事务subts2 using (TransactionScope subts2 =new TransactionScope (TransactionScopeOption.Required)) { //创建数据库连接类实例2 SqlConnection conn2 = new SqlConnection(ConnectionString2); //将在数据库连接实例2上执行的命令 SqlCommand command = new SqlCommand(@"INSERT Shippers (CompanyName,Phone) VALUES('Test Ship2','0000-0002')",conn2); conn2.Open(); command.ExecuteNonQuery();//执行数据库操作 conn2.Close(); subts2.Complete();//完成子事务 } //完成ts1事务的语句,去掉注释后subts2的事务才能提交 //ts1.Complete(); //连接数据库的字符串3 string ConnectionString3 = @"Data Source = localhost; Initial Catalog = Northwind; Integrated Security = SSPI;"; //创建数据库连接类实例3 SqlConnection conn3 = new SqlConnection(ConnectionString3); //打开数据库连接 conn3.Open(); //读取数据库中Shippers表的数据 SqlDataReader dr = new SqlCommand("SELECT * FROM Shippers", conn3).ExecuteReader(); while (dr.Read()) //循环显示数据 { Console.WriteLine("{0} {1} {2}", dr.GetInt32(0).ToString(), dr.GetString(1), dr.GetString(2)); } dr.Close();//关闭SqlDataReader类实例 conn3.Close();//关闭数据库连接类实例 Console.ReadLine(); } } } } |
1 Speedy Express (503) 555-9831 2 United Package (503) 555-3199 3 Federal Shipping (503) 555-9931 4 Test Ship1 0000-0001 |
(1)本示例程序定义了一个外部的事务范围ts1,在该范围内分别使用TransactionScopeOption枚举的RequiresNew 成员和Required成员创建了两个事务范围。在这两个事务范围内,分别创建数据库连接,并执行SQL命令语句。然后在事务范围之外,查询并显示数据库 中的表记录,以检查事务的提交情况。本示例程序的流程图如图13.2所示。
498)this.style.width=498;" border=0> |
图13.2 使用TransactionScopeOption实现事务选项控制的示例程序流程图 |
(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服务器。
相关文章推荐
- 使用TransactionScope实现多数据库连接事务操作
- 使用TransactionScope实现多数据库连接事务操作
- 使用TransactionScope实现多数据库连接事务操作
- 使用TransactionScope实现单数据库连接事务操作
- PHP入门教程之使用Mysqli操作数据库的方法(连接,查询,事务回滚等)
- 使用VS2010连接SQL Server 2008数据库混合编程以实现对数据库的操作
- C#使用COM+实现事务控制,操作多个数据库
- PHP入门教程之使用Mysqli操作数据库的方法(连接,查询,事务回滚等)
- PHP入门教程之使用Mysqli操作数据库的方法(连接,查询,事务回滚等)
- 详解连接SQL Server数据库的方法,并使用Statement接口实现对数据库的增删改操作
- TransactionScope 实现多数据库连接事务操作 (转)
- 使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
- TransactionScope实现多数据库连接事务操作
- 使用c3p0连接数据库、操作数据库和数据库的事务管理,基于mybatis框架
- 通过代理类实现java连接数据库(使用dao层操作数据)实例分享
- mySql事务_ _Java中怎样实现批量删除操作(Java对数据库进行事务处理)?
- Spring整合Hibernate开发 - 使用事务管理器操作数据库 - 主配置文件
- Python使用Flask-SQLAlchemy连接数据库操作示例
- 使用package(包功能)实现DLL与主程序的数据库连接共享(Delphi版)
- 使用连接池和缓存机制,处理连接数据库操作