Transcation Scope,使代码块成为事务性代码
2006-08-07 13:17
190 查看
分布式事务(DTx:Distributed Transaction)一直是大型应用所需的必要特性,由于需要同时协调不同的数据源(例如:数据库、队列、甚至注册表和新一代操作系统的I/O),因此启动DTx的代价相对较大,而且很多中间件服务器的DTx协调器与应用位于不同的进程中,
// This function takes arguments for 2 connection strings and commands to create a transaction
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the
// transaction is rolled back. To test this code, you can connect to two different databases
// on the same server by altering the connection string, or to another RDBMS such as Oracle
// by altering the code in the connection2 code block.
static public int CreateTransactionScope(
string connectString1, string connectString2,
string commandText1, string commandText2)
{
// Initialize the return value to zero and create a StringWriter to display results.
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
try
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
try
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
catch (Exception ex)
{
// Display information that command2 failed.
writer.WriteLine("returnValue for command2: {0}", returnValue);
writer.WriteLine("Exception Message2: {0}", ex.Message);
}
}
catch (Exception ex)
{
// Display information that command1 failed.
writer.WriteLine("returnValue for command1: {0}", returnValue);
writer.WriteLine("Exception Message1: {0}", ex.Message);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
// The returnValue is greater than 0 if the transaction committed.
if (returnValue > 0)
{
writer.WriteLine("Transaction was committed.");
}
else
{
// You could write additional business logic here, for example, you can notify the caller
// by throwing a TransactionAbortedException, or logging the failure.
writer.WriteLine("Transaction rolled back.");
}
// Display messages.
Console.WriteLine(writer.ToString());
return returnValue;
}
因此对于频繁提交的OLTP操
4000
作而言性能影响较大。
。NET Framework 2.0开始默认提供ORACLE的ADO.NET驱动,虽然也支持通过TransactionScope隐式启动DTx,但却采用应用宿主进程外的dllhost.exe作为独立的DTx协调器(DTC)。ORACLE在自己的ADO.NET驱动中对该问题进行了显着优化,不仅对反复打开的连接提供了默认的连接池引用重定向,而且把DTx的协调工作置于。NET CLR与应用宿主内部,对于大型应用而言可以有效的减少因跨多进程协调引发的性能损失。
下面的示例代码采用ORACLE的ADO.NET驱动(using Oracle.DataAccess.Client)运行,从COM+的统计看并不会引起DTC调用,而如果换成微软的ORACLE ADO.NET驱动(using System.Data.OracleClient),就需要启动昂贵的DTC服务。
// This function takes arguments for 2 connection strings and commands to create a transaction
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the
// transaction is rolled back. To test this code, you can connect to two different databases
// on the same server by altering the connection string, or to another RDBMS such as Oracle
// by altering the code in the connection2 code block.
static public int CreateTransactionScope(
string connectString1, string connectString2,
string commandText1, string commandText2)
{
// Initialize the return value to zero and create a StringWriter to display results.
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
try
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
try
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
catch (Exception ex)
{
// Display information that command2 failed.
writer.WriteLine("returnValue for command2: {0}", returnValue);
writer.WriteLine("Exception Message2: {0}", ex.Message);
}
}
catch (Exception ex)
{
// Display information that command1 failed.
writer.WriteLine("returnValue for command1: {0}", returnValue);
writer.WriteLine("Exception Message1: {0}", ex.Message);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
// The returnValue is greater than 0 if the transaction committed.
if (returnValue > 0)
{
writer.WriteLine("Transaction was committed.");
}
else
{
// You could write additional business logic here, for example, you can notify the caller
// by throwing a TransactionAbortedException, or logging the failure.
writer.WriteLine("Transaction rolled back.");
}
// Display messages.
Console.WriteLine(writer.ToString());
return returnValue;
}
因此对于频繁提交的OLTP操
4000
作而言性能影响较大。
。NET Framework 2.0开始默认提供ORACLE的ADO.NET驱动,虽然也支持通过TransactionScope隐式启动DTx,但却采用应用宿主进程外的dllhost.exe作为独立的DTx协调器(DTC)。ORACLE在自己的ADO.NET驱动中对该问题进行了显着优化,不仅对反复打开的连接提供了默认的连接池引用重定向,而且把DTx的协调工作置于。NET CLR与应用宿主内部,对于大型应用而言可以有效的减少因跨多进程协调引发的性能损失。
下面的示例代码采用ORACLE的ADO.NET驱动(using Oracle.DataAccess.Client)运行,从COM+的统计看并不会引起DTC调用,而如果换成微软的ORACLE ADO.NET驱动(using System.Data.OracleClient),就需要启动昂贵的DTC服务。
private const string ConnectionString = "Data Source = localhost:1521/XE; User ID = scott; Password = tiger"; private const string SqlConnectionString = "Data Source = (local); Initial Catalog = Northwind; Integrated Security = SSPI"; [TestMethod] public void TestOracleDriver() { using (TransactionScope scope = new TransactionScope()) { Oracle.DataAccess.Client.OracleConnection connection = new Oracle.DataAccess.Client.OracleConnection(ConnectionString); connection.Open(); Oracle.DataAccess.Client.OracleCommand command = connection.CreateCommand(); command.CommandText = "UPDATE DEPT SET DNAME = DNAME"; command.CommandType = CommandType.Text; command.ExecuteNonQuery(); // 为了模拟一个分布式数据的操作,下面还增加了一段SqlConnection的DML操作。 SqlConnection sqlC = new SqlConnection(SqlConnectionString); sqlC.Open(); SqlCommand sComm = sqlC.CreateCommand(); sComm.CommandText = "UPDATE Products SET ProductName = ProductName"; sComm.CommandType = CommandType.Text; sComm.ExecuteNonQuery(); scope.Complete(); } } [TestMethod] public void TestMicrosoftDriver() { using (TransactionScope scope = new TransactionScope()) { System.Data.OracleClient.OracleConnection connection = new System.Data.OracleClient.OracleConnection(ConnectionString); connection.Open(); System.Data.OracleClient.OracleCommand command = connection.CreateCommand(); command.CommandText = "UPDATE DEPT SET DNAME = DNAME"; command.CommandType = CommandType.Text; command.ExecuteNonQuery(); // 为了模拟一个分布式数据的操作,下面还增加了一段SqlConnection的DML操作。 SqlConnection sqlC = new SqlConnection(SqlConnectionString); sqlC.Open(); SqlCommand sComm = sqlC.CreateCommand(); sComm.CommandText = "UPDATE Products SET ProductName = ProductName"; sComm.CommandType = CommandType.Text; sComm.ExecuteNonQuery(); scope.Complete(); } } |
相关文章推荐
- Transcation Scope,使代码块成为事务性代码
- TransactionScope 类,使代码块成为事务性代码。无法继承此类。
- 构造函数、构造代码块、静态成员、静态代码块
- Java中静态代码块,代码块,构造方法优先级、区别及代码示例
- 普通代码块,静态代码块和构造代码块
- 普通代码块、静态代码块和构造代码块
- 大牛养成指南(3):天天写业务代码,如何成为技术大牛?
- 天天写业务代码,如何成为技术大牛?
- 汉字转拼音缩写示例代码(Silverlight和.NET 将汉字转换成为拼音)
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- 人会成为虚拟现实中的“机器人代码”吗?
- 天天写业务代码,如何成为技术大牛?
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- final、static、代码块、静态代码块、内部类、代码执行顺序
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- Java类中代码的执行顺序 静态代码块>构造代码块>构造方法
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- 面向对象 构造代码块 静态代码块
- 解决“Visual Studio 要求设计器使用文件中的第一个类。移动类代码使之成为文件中的第一个类,然后尝试重新加载设计器。”方法