如何在 Visual C# 组件中使用 COM+ 事务

文章翻译 文章翻译
文章编号: 816141 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

概要

本文分步介绍了如何在 Visual C# 类中使用 COM+(组件服务)事务。一组数据库操作被视为一个事务单元。要么所有的操作都成功;要么如果其中一个操作失败,则整个事务失败。对于后一种情况,所尝试的任何数据库操作都不会发布到基础数据库中。

要求

下面几项介绍了推荐使用的硬件、软件、网络基础结构、技能和知识以及必需的 Service Pack:
  • Microsoft Windows 2000 Server SP1
  • Microsoft Internet 信息服务 (IIS) 4.0 或更高版本
  • Microsoft Internet Explorer 5.0、5.5 或 6.0 版
本文假定您已熟悉以下主题:
  • 事务的概念和处理
  • COM+(组件服务)

COM+ 事务服务

您可以使用 Microsoft .NET Framework 中的 System.EnterpriseServices 命名空间来实现事务处理。要访问 COM+ 事务服务,需创建一个类。为此,请按照下列步骤操作:
  1. 启动 Visual Studio .NET 或 Visual Studio 2005。
  2. 在“文件”菜单上,指向“新建”,然后单击“项目”。
  3. 单击“项目类型”下的“Visual C# 项目”,然后单击“模板”下的“类库”。将该项目命名为 prjEnterprise

    注意:在 Visual Studio 2005 中,请单击“项目类型”下的“Visual C#”,然后单击“模板”下的“类库”。将该项目命名为 prjEnterprise
  4. 默认情况下将创建 Class1。
  5. 在解决方案资源管理器中,右键单击“引用”,然后单击“添加引用”。
  6. 将出现“添加引用”对话框。在“.NET”选项卡的“组件名称”下,双击“System.EnterpriseServices”。
  7. 确保“System.EnterpriseServices”显示在“选定的组件”下。单击“确定”。
  8. 将以下代码添加到 Class1.cs 文件中的其他任何语句之前:
    using System.EnterpriseServices;
    using System.Data.SqlClient;
  9. 向 Class1.cs 文件中添加一个名为 clsES 的新类。
  10. 要使用 COM+ 事务服务,您的类 (clsES) 必须按如下方式从 ServicedComponent 继承功能:
    public class clsES : ServicedComponent
  11. 按如下方式使用一个 Transaction 属性来指定该类的事务支持级别:
    [Transaction(TransactionOption.Required)]public class clsES : ServicedComponent
  12. clsES 类中创建一个方法,然后将其命名为 dbAccess,该方法接收四个整数作为输入参数。前两个参数提供一个产品 ID 和这种产品的订货数量;后两个参数提供一个产品 ID 和这种产品的库存数量。该方法对这些指定的产品 ID 执行一组数据库操作,这组数据库操作将被视为一个事务:
    void dbAccess(int pID1,int onOrder, int pID2, int inStock)
  13. dbAccess 方法中,创建一个用于罗斯文数据库的 SQL 连接对象,然后打开该连接。数据库操作是使用以下数据库进行的:

    注意:不要忘记更改下面的连接字符串参数以反映您的 SQL Server 服务器的正确值。
    SqlConnection Conn = new SqlConnection("user id=<username>;password=<strong password>;Initial Catalog=northwind;Data Source=2E124\\SQL;");
    				Conn.Open();
    
  14. 设置一个 try 块以捕获在数据库处理过程中可能出现的任何异常。您必须捕获这些异常来终止事务。try 块包括两个数据库操作,每个操作更新指定的 Products 表记录中的一个不同字段。
     try { 
    
  15. 对 Products 表执行第一个更新。按照前两个输入参数的指定,使用 onOrder 值更新具有指定 ID 的产品的 UnitsonOrder 字段。使用下面的 SQL 命令运行这个 SQL 更新:
    SqlCommand sqlCommand = new SqlCommand("UPDATE myProducts SET UnitsonOrder = " + onOrder + " WHERE productID = " + pID1, Conn);
    				sqlCommand.ExecuteNonQuery();
  16. 对 Products 表执行另一个更新。按照第三个和第四个输入参数的指定,使用 inStock 值更新具有指定 ID 的产品的 UnitsinStock 字段。使用下面的 SQL 命令运行这个 SQL 更新:
    sqlCommand.CommandText = "UPDATE myProducts SET UnitsinStock = " + inStock + " WHERE productID = " + pID2;
    				sqlCommand.ExecuteNonQuery();
    
  17. 因为这些更新是 COM+ 事务的一部分,所以它们作为一个单元提交。如果没有引发错误,将使用 System.EnterpriseServices 命名空间中的 contextUtil 类的 setComplete 方法提交该事务(在本例中是两个更新):
    ContextUtil.SetComplete();
  18. 与罗斯文数据库的连接关闭:
    Conn.Close();
    }
  19. 您必须捕获运行 SQL 命令时发生的任何异常以便能够终止整个事务:
    catch(Exception e){ 
  20. 使用 System.EnterpriseServices 命名空间中的 contextUtil 类的 setAbort 方法终止整个事务。如果第一个更新成功但第二个更新失败,则两个更新都不会发布到 Products 表。捕获到的异常将抛给调用者,表明事务已失败:
    ContextUtil.SetAbort();
    				throw e;
    }
  21. 为使该组件正确运行,该组件必须有一个强名称。生成一个强名称,然后使用该强名称对程序集进行签名。为此,请按照下列步骤操作:
    1. 在 Visual Studio .NET 命令提示符处,键入 sn.exe -k snEnterprise.snk 以创建一个密钥文件。有关使用强名称对程序集进行签名的更多信息,请参见 .NET Framework SDK 文档。
    2. 将 snEnterprise.snk 复制到您的项目文件夹中。
    3. 在 AssemblyInfo.vc 中,将以下代码行添加到其他程序集属性语句之前或之后:
      [assembly: AssemblyKeyFileAttribute("..\\..\\snEnterprise.snk")]		
    4. 进行保存,然后生成您的项目。

完整代码列表



注意:不要忘记更改下面的连接字符串参数以反映您的 SQL Server 服务器的正确值。
using System;
using System.Data;
using System.Data.SqlTypes;
using System.Data.Common;
using System.EnterpriseServices;
using System.Data.SqlClient;

namespace prjEnterprise
{
	
	[Transaction(TransactionOption.Required)]public class clsES:ServicedComponent
	{
		public SqlConnection Conn;

		public void dbAccess(int pID1, int onOrder, int pID2, int inStock)
		{
			try
			{			
				SqlConnection Conn = new SqlConnection("user id=<username>;password=<strong password>;Initial Catalog=northwind;Data Source=2E124\\SQL;");
				Conn.Open();
				
SqlCommand sqlCommand = new SqlCommand("UPDATE myProducts SET UnitsonOrder = " + onOrder + " WHERE productID = " + pID1, Conn);
				sqlCommand.ExecuteNonQuery();
				
				sqlCommand.CommandText = "UPDATE myProducts SET UnitsinStock = " + inStock + " WHERE productID = " + pID2;
				sqlCommand.ExecuteNonQuery();

				ContextUtil.SetComplete();
				Conn.Close();
			}
			catch(Exception e)
			{
				ContextUtil.SetAbort();
			
				throw e;
			}
			finally
			{

			}
		}
	}	
}

确认它可以使用

要测试这个代码,需要创建一个使用 clsES 项目的控制台应用程序。一种情形是:事务成功,指定产品的 onorderinstock 字段得到了更新。另一种情形是:对一个指定产品的 onOrder 字段的更新成功了,但对另一个指定产品的 inStock 字段的更新失败了(因为在 Products 表中不存在指定的产品编号)。这会导致事务失败,该事务将被忽略。
  1. 在 Visual Studio .NET 或 Visual Studio 2005 中,指向“文件”菜单上的“新建”,然后单击“项目”。
  2. 单击“项目类型”下的“Visual C# 项目”,然后单击“模板”下的“控制台应用程序”。

    注意:在 Visual Studio 2005 中,请单击“项目类型”下的“Visual C#”,然后单击“模板”下的“控制台应用程序”。
  3. 在“名称”文本框中,键入 testES。确保已选中了“添入解决方案”选项。
  4. 单击“确定”将该项目添加到解决方案中。
  5. 要使 testES 测试 clsES,您必须添加一个引用。在解决方案资源管理器中,右键单击 testES(您刚才添加的)下的“引用”,然后单击“添加引用”。
  6. 将出现“添加引用”对话框。在“项目”选项卡上,双击“prjEnterprise”。
  7. 在“选定的组件”下显示一个引用。单击“确定”向项目中添加该引用。
  8. 在项目中添加对 System.EnterpriseServices 库的引用。在解决方案资源管理器中,右键单击“引用”,然后单击“添加引用”。
  9. 将出现“添加引用”对话框。在“.NET”选项卡的“组件名称”下,双击“System.EnterpriseServices”。
  10. 确保“System.EnterpriseServices”显示在“选定的组件”下。单击“确定”。
  11. 右键单击控制台应用程序 (testES),然后单击“设为启动项目”。
  12. 将以下源代码粘贴到 Class1 类的 Main 函数中:
    	prjEnterprise.clsES myTest = new prjEnterprise.clsES();
    
    				try 
    				{
    					myTest.dbAccess(1, 777, 2, 888);
    					Console.WriteLine("TRANSACTION ONE -- SUCCESS");
    
    					myTest.dbAccess(1, 5, 2, -20);
    					Console.WriteLine("TRANSACTION TWO -- SUCCESS");
    				}
    				catch (Exception e)
    				{
    					Console.WriteLine("TRANSACTION FAILURE");
    				}
  13. 按 F5 以运行测试代码。

    在代码的步骤 7 中,对 dbAccess 的第一个调用成功完成。产品 1 和产品 2 均在 Products 表中。产品 1 的 onOrder 字段更新为 777,产品 2 的 inStock 字段更新为 888。因为这个事务成功完成,所以您将在输出窗口中收到以下消息
    事务 1 - 成功


    dbAccess 的第二个调用失败。因此,不会将 dbAccess 中的对 Products 表的任何更新语句发布到数据库。虽然产品 1 本来可以将它的 onOrder 字段更新为 5,但是产品 2 不能将它的 inStock 字段设为 -20。(因为 Products 表定义中定义的一个约束条件规定 inStock 不允许为负数)。

    因此,对 dbAccess 的这个调用失败了,从而整个事务也随之失败。Products 表将保持调用 dbAccess 之前的状态。catch 语句处理来自 dbAccess 的事务失败通知,您将在输出窗口中收到以下错误消息:
    TRANSACTION FAILURE
  14. 使用 SQL Server 企业管理器检查罗斯文的 Products 表的内容。查看产品 1,onOrder 字段的值为 777。查看产品 2,instock 字段的值为 888。因此,对 dbAccess 的第二个调用(此调用本会使这些字段具有不同的值)失败了。

疑难解答

  • 确保使用 COM+ 服务的所有项目都有一个强名称。
  • 使用 COM+ 服务的所有类都必须继承服务组件。服务组件位于 System.EnterpriseServices 命名空间中。
  • 进行调试时,事务在提交或终止前可能会超时。要避免出现超时,请在事务属性中使用一个超时属性。在下面的示例中,在完成任何事务时,关联的方法在超时前都有 1,200 秒的执行时间:
    [Transaction(TransactionOption.Required,timeout:=1200)]

参考

有关其他信息,请访问下面的 Microsoft Developer Network (MSDN) 网站:
COM+ 集成:.NET Enterprise Services 如何帮助您生成分布式应用程序
http://msdn.microsoft.com/msdnmag/issues/01/10/complus/default.aspx
服务组件:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/f_and_m/html/vxconInterop.asp

属性

文章编号: 816141 - 最后修改: 2006年10月4日 - 修订: 3.2
这篇文章中的信息适用于:
  • Microsoft Visual C# .NET 2003 标准版
  • Microsoft Visual C# .NET 2002 标准版
  • Microsoft Visual C# 2005
关键字:?
kbcomplusobj kbsqlprog kbsqlclient kbdatabase kbhowtomaster KB816141
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com