zoukankan      html  css  js  c++  java
  • Transcation Scope,使代码块成为事务性代码

    分布式事务(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操作而言性能影响较大。

      。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();
    }
    }

  • 相关阅读:
    Codeforces 1354C2
    Codeforces 1354C1
    Codeforces 1355C
    Codeforces 1353D
    Codeforces 1352
    Codeforces 1351C
    Codeforces 1344B/1345D
    Codeforces 1342D
    Codeforces 1340B/1341D
    Codeforces 1343D
  • 原文地址:https://www.cnblogs.com/zyizyizyi/p/2497853.html
Copyright © 2011-2022 走看看