在本人最近的几篇关于事务处理的文章中,从事务处理的整体概念到具体的C#代码的实践操作基本上都已经能满足日常的开发需求。文章中大部分的事务范围类的操作都是局限于数据库,在本人的“.NET简谈自定义事务资源管理器 ”一文中我虽然实现了一个简单的自定义资源管理器,其实也能满足基本的项目需求,核心功能也实现了,但是对于文件事务操作我们是力不从心的。[王清培版权所有,转载请给出署名]
从数据库到自定义资源管理器都能参与到事务处理中来,在必要的时候保证数据的完整性,那么我们缺一个类型的资源操作,当然您也许早就想问了,关于文件系统的事务操作怎么办?那么关于文件的事务操作是否有成熟的解决方案了,这点在前几年还真没办法,但是最近微软已经发布了关于事务性NTFS系统。都了解NTFS文件系统的优势和好处,比起FAT和其他的什么HPFS文件系统有极大的改进,所以文件事务处理仅支持NTFS格式的文件系统。
事务性NTFS也称做TXF,只有最新的Windows系统才支持(WindowsVistaWindows7WindowsServer2008WindowsServer2008R2),所以在XP上就别测试了。[王清培版权所有,转载请给出署名]
在前几篇文章中都是使用的LTM本地事务管理器,然后进行事务范围类的多个持久资源登记自动事务提升为DTC类型的事务操作,由于DTC是非托管的实现,所以在分布式事务操作中会存在数据封送的性能损耗,MSDN也提倡尽量少用DTC处理,由于存在着很多不确定因素在遇到问题时比较棘手。但是在关键的时候还是需要这么用的,我们有必要去研究研究。
KTM、DTC、LTM三者的使用关系简单介绍
以前的理解思路和讲解的角度对于KTM来说是没多大关系的,但是由于他的出现我们有必要回归到原点进行重新的梳理来进行一个更加系统深入的理解,仅仅是理解;
在查询了大量的MSDN文档和对System.Transaction命名空间的仔细翻阅发现微软隐藏了很多.NET事务实现细节,比如System.Transaction.Oletx命名空间下的具体分布式协议的实现是没有任何技术文档看的,只能反编译自己看代码琢磨。
我们从LTM进行梳理,LTM是本地事务管理器那么他的存在只能在当前的托管AppDomain中,不能够夸远程处理,一旦跨远程处理负责传播的对象就要实现对本地事务的提升功能,包括WCF中的一系列的banding元素和事务感知型代码,都必须对事务进行管理,但是大部分的代码都是系统提供的。[王清培版权所有,转载请给出署名]
反编译看了部分代码,其中都会涉及到PInvoke和COMInterop之类的代码,凭自己的理解它的目的是启动IDTCTransaction接口,也就是COM接口。理解这一点对于我们下面的KTM操作非常有利。LTM要想进行DTC管理就必须通过OLE32.DLL进行COM接口的加载也就是我们托管的.NET类库里面的IDTCTransaction接口,看一下代码:
代码语言:javascript复制// Describes a DTC transaction.
[Guid("0fb15084-af41-11ce-bd2b-204c4f4f5020")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDtcTransaction
该接口是向COM公开时的类型,用作于COM互操作使用的,需要通过该接口进行DTC的提升使用;为了验证理解是否正确我们来进行一个简单的测试,我们手动的通过System.Transaction.TransactionInterop类来获取非托管的IDTCTransaction接口,请看代码:
LTM事务:
代码语言:javascript复制public static void StartCopy()
{
using (TransactionScope transcope = new TransactionScope())
{
transcope.Complete();
}
}
这样的代码是不会提升为DTC管理的,我们加一行代码:
代码语言:javascript复制public static void StartCopy()
{
using (TransactionScope transcope = new TransactionScope())
{
IDtcTransaction idtc = TransactionInterop.GetDtcTransaction(Transaction.Current);
transcope.Complete();
}
}
先解释一下TransactionInterop类的作用,来自MSDN的说明:
“促进System.Transactions 和以前编写的用于与 MSDTC、COM 或 System.EnterpriseServices 进行交互的组件之间的交互。无法继承此类。”
其实该类主要用来对早期的分布式事务技术进行互操作,比如用来获取DTC相关的COM对象或者用来进行自定义的事务传播,对于复杂的Oletx(Windows平台的二进制通讯协议)协议,我们不需要关心太多核心的东西就能进行分布式事务的传递,这里可能Remoting有这个需求了。[王清培版权所有,转载请给出署名]
利用TransactionInterop.GetDtcTransaction方法确实能获取到DTC事务接口。
图1:
有了TransactionInterop类,我们后面的扩展就方便多了。
由于KTM是属于非托管实现,操作系统提供了文件操作的事务性API方法:
非事务处理 API | 事务处理 API |
---|---|
CreateFile | CreateFileTransacted |
CopyFileEx | CopyFileTransacted |
MoveFileWithProgress | MoveFileTransacted |
DeleteFile | DeleteFileTransacted |
CreateHardLink | CreateHardLinkTransacted |
CreateSymbolicLink | CreateSymbolicLinkTransacted |
CreateDirectoryEx | CreateDirectoryTransacted |
RemoveDirectory | RemoveDirectoryTransacted |
通过封装这些方法就能够实现事务性的文件操作,目前.NET没有封装成熟的类库给我们使用,估计在后期的新版本类库中可能会提供。
那么我们如何使用KTM事务处理呢,很幸运的是通过MSND的连接我们能够获取到微软的事务开发人员编写的源码,下载地址为:
http://download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/TxF2007_07.exe
源码都是通过对上面的API进行封装的,里面涉及到了很多关于内部API和COM之间的通讯细节,我们可以看看老外写的代码是复杂,也是我们学习的榜样。
上面我们说过只要夸当前应用程序域的事务处理就会自动提升为DTC事务,对于API的调用已经是出于互操作类型的,当前已经出于远程调用,DTC已经具有与托管域的交互实现,所以我们只有通过DTC进入KTM进行操作。这也是MSDN官方的解释。
图2:
我们来看一个简单的例子,该例子实现对文件的事务性删除操作。
例子1:
代码语言:javascript复制public static void StartDelete()
{
try
{
using (TransactionScope transcope = new TransactionScope())
{
Console.WriteLine("输入要删除的文件");
string path = Console.ReadLine();
Microsoft.KtmIntegration.TransactedFile.Delete(path);
Console.WriteLine("是否提交事务处理?");
if (Console.ReadLine() == "y")
transcope.Complete();
else
Transaction.Current.Rollback();
}
}
catch (Exception err) { Console.WriteLine(err); }
我简单的写了一段测试代码,经过测试是OK的。KTM能很好的结合DTC、LTM进行混合的事务处理,对于我们上面引入的疑问现在能完美的解决了。
参考文章:http://msdn.microsoft.com/zh-cn/magazine/cc163388.aspx