.NET程序员的分布式事务与NHibernate整合

在.NET编程环境中,分布式事务管理和对象关系映射(ORM)是两个非常强大的工具。本文将展示如何将这两个工具简单地结合起来使用。

分布式事务是使用COM+时最喜欢的部分。通过开启一个分布式事务,可以将不同的数据库、消息队列、文件、电子邮件等几乎所有能想到的东西纳入同一个事务中。两阶段提交机制告诉,要么全部成功,要么全部回滚。如果服务器宕机,事务还可以从上次中断的地方重新开始。

NHibernate是另一个喜欢使用的强大工具。如果不熟悉这个ORM(对象关系映射器),可以点击访问主站。NHibernate是基于标准ADO.NET构建的,并且具有使用事务的能力。但普通的ADO.NET事务只限于一个数据库连接。COM+的分布式事务可以跨越多个数据源。希望NHibernate代码能够参与到分布式事务中。本文将展示是如何实现这一点的。

使用代码

在代码中,有几件事情应该了解:

COM+项目有一个后构建步骤。后构建使用regsvcs来注销并重新注册COM+ DLL。这增加了编译的等待时间,但省去了手动操作的麻烦。为了让regsvcs工作,将框架目录添加到了路径中(C:\Windows\Microsoft.NET\Framework\v1.1.4322)。像往常一样,如果改变了路径变量,必须重启Visual Studio。

还创建了一个NUnit测试项目来运行实际的测试。在测试项目的后构建中,将App.Config复制到目标目录,并给它添加了".config"后缀。这样NUnit就可以找到它了。

通常,将测试项目设置为启动项目。要让NUnit启动项目,请打开项目属性窗口,选择左侧的Configuration Properties->Debugging。将Debug Mode设置为Program,然后点击Apply。对于启动应用程序,找到NUnit GUI可执行文件(C:\Program Files\NUnit 2.2\bin\nunit-gui.exe)。对于命令行参数,输入DLL的文件名(CPNTestHarness.dll)。

包含了一个SQL脚本来创建在示例中使用的表。将这些表放入数据库,并更改App.Config中的连接字符串。

可能注意到了设置NHibernate配置的奇怪方式。没有使用App.Config来设置它,而是用代码从App.Config中提取连接字符串。这只是个人偏好。通常发现,在企业环境中App.Config是不够的,通常会从Microsoft企业库中提取配置设置。所以快速更改了代码以适应这个示例。

OrmManager类

这个类基本上是处理与NHibernate通信的方式。它创建配置并获取ISessionFactory。它只为这个示例暴露了三个方法:Save(object)、Delete(object)和GetAll(Type)。这些对普通的NHibernate用户来说应该都很熟悉。没有包括特定的获取方法,因为不需要它来进行测试。

整篇文章的真正重点围绕EnlistIfPossible()方法。当使用常规的ADO.NET时,可以通过使用EnlistDistributedTransaction方法将数据库连接注册到COM+分布式事务中。不幸的是,这个方法不是任何接口的一部分。它也不是System.Data.IDbConnection类的一部分,这基本上是NHibernate会给所有。知道的是,大多数IDbConnection的实现都有一个EnlistDistributedTransaction方法。一个例外是System.Data.SqlServerCe库。

为了让连接参与分布式事务,只需要在连接对象上调用EnlistDistributedTransaction方法(如果它存在)。为了做到这一点,使用了反射:

private static void EnlistIfPossible(System.Data.IDbConnection conn) { if (ContextUtil.IsInTransaction) { MethodInfo mi = conn.GetType().GetMethod("EnlistDistributedTransaction", BindingFlags.Public | BindingFlags.Instance); if (mi != null) { mi.Invoke(conn, new object[] { (System.EnterpriseServices.ITransaction)ContextUtil.Transaction }); } } }

非常简单。现在,每当打开一个NHibernate会话时,都可以将数据库连接注册到COM+事务中。这在Save和Delete中完成。

TransactionController类

OrmManager将参与事务(如果存在)。但如果不存在事务,它不会创建新的事务。这样用户可以选择是否进行事务处理。为了处理事务,有一个类包装了OrmManager,叫做TransactionController。这个类基本上允许开始和结束事务,并在中间做一大堆ORM代码。

开始和结束事务是一段标准的COM+代码:

public void BeginTransaction() { ServiceConfig sc = new ServiceConfig(); sc.Transaction = TransactionOption.RequiresNew; ServiceDomain.Enter(sc); ContextUtil.MyTransactionVote = TransactionVote.Commit; ... } public void EndTransaction() { if (ContextUtil.MyTransactionVote == TransactionVote.Commit) ContextUtil.SetComplete(); else ContextUtil.SetAbort(); ServiceDomain.Leave(); ... }

测试框架

NUnit测试框架展示了如何使用代码:

TransactionController tc = new TransactionController(); Table1 t1; // NHibernate对象 Table2 t2; // NHibernate对象 try { tc.BeginTransaction(); t1 = new Table1(); t1.Num = 1; t2 = new Table2(); t2.Num = 2; tc.Save(t1); tc.Save(t2); } finally { tc.EndTransaction(); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485