zoukankan      html  css  js  c++  java
  • 使用TransactionScope实现单数据库连接事务操作

    当应用程序需要在多个数据库中进行事务性操作的时候,使用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,即在 事务过程中,完全性锁表。别的进程不能查询,修改,新增,删除。这样会导致效率大大降低,虽然数据完整性很高。通常我们不需要那么高的数据完整性。所以需 要修改默认的事务级别:

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

    (3)按F5键运行程序,运行结果如下所示。
    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所示。

      
    图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服务器。

  • 相关阅读:
    JAVA 网格布局管理器
    JAVA 流式布局管理器
    JAVA 边界布局管理器
    JAVA 图形界面 JFrame容器
    MySQL联合查询语法内联、左联、右联、全联
    ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL
    ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL
    MVC过滤器详解
    Dapper的基本使用
    JQuery fullcalender文档
  • 原文地址:https://www.cnblogs.com/haoliansheng/p/1409286.html
Copyright © 2011-2022 走看看