.NET简谈自定义事务资源管理器

在上一篇文章“NET简谈事务、分布式事务处理”中我大概总结了关于.NET中的事务处理方式和结合了WCF框架的简单应用。在事务性操作中我们的重点是能将数据进行可逆化,说白了就是能保证数据的ACID(关于事务的整体模型、原理请参见“.NET简谈事务本质论”一文),在.NET事务处理框架中强大的类库帮我们实现了很多事务传递、事务自动提升的技术难点,同时也提供了很多扩展接口,只要我们肯去研究总能有收获。

这篇文章主要讲解怎样利用.NET为我们提供的扩展接口进行自定义的事务处理范围内的资源管理,在事务的操作范围内我们不会总是将数据库视为依赖的对象,也不会总是IdbTransaction之类的对象,我们需要自己的事务性资源管理器,我们需要自己的持久性资源管理器。在可能的情况下我们需要自己开发后备持久存储区。

有兴趣的朋友可以去看看我们蒋金楠蒋大哥的关于事务的文章,讲的非常好:http://www.cnblogs.com/artech/archive/2010/01/31/1660433.html

下面我们将实现一个简单的事务性资源管理器,在此先解释一下关于事务性资源管理器的意思。在我们日常开发过程中,大部分的数据都是存储于数据库中,事务范围内的操作不允许对非事务性资源进行修改因为他们是不可逆的,没有资源管理器对他们进行管理,当事务出错时无法将修改后的数据恢复到事务操作之前的状态,我们只能对数据库中的数据进行修改然后执行回滚,因为数据库中的数据有数据库资源管理器进行强大的管理。[王清培版权所有,转载请给出署名]

当我们使用IdbTransaction进行事务处理时其实是获取对远程事务处理的一个引用,比如SqlTransaction对象他就是逻辑上的事务资源管理器,当我们使用TransactionScope进行事务范围操作时,SqlServer数据提供程序能进行自动的事务提升并且进行事务资源登记,在最后能很好的进行二阶段提交协议进行数据的最终提交。

 

事务性资源管理器分类:

.NET事务模型提供了几个接口方便我们实现自定义的资源管理器,我们可以通过继承这些接口实现支持单阶段、两阶段提交协议的资源管理器。

1.IenlistmentNotification接口:支持两阶段提交协议的资源管理器实现接口。

(官方解释:描述资源管理器为了在登记参与时为事务管理器提供两阶段提交通知回调而应该实现的接口。)

2.IsinglePhaseNotification接口:支持单阶段协议的资源管理器实现接口。

(官方解释:描述支持单阶段提交优化以参与事务的资源对象。)

3. IpromotableSinglePhaseNotification接口:支持可提升的单阶段提交协议的资源管理器实现接口。(官方解释:描述作为资源管理器内部非分布式事务的提交委托的对象。)这个对象继承自ItransactionPromoter接口,该接口需要自动提升为由MSDTC管理的资源管理器使用的。

 

实现System.Transactions.IenlistmentNotification接口,自定义两阶段提交协议的资源管理器

下面我们通过实现IenlistmentNotification接口来开发一个简单的资源管理器。

代码1:资源管理器

public class IEnlistmentNotificationDemo<T, Xcopy> : IEnlistmentNotification
        where T : new()
        where Xcopy : class
    {
        T _commitfrontvalue;
        T _rollbackfrontvalue = new T();
        Xcopy copy;
        public IEnlistmentNotificationDemo(T t, Xcopy icopy)
        {
            (icopy as IResourceCopy<T>).Copy(_rollbackfrontvalue, t);
            _commitfrontvalue = t;//保持对资源修改的引用
            copy = icopy;
        }

        #region IEnlistmentNotification 成员
        public void Prepare(PreparingEnlistment preparingEnlistment)
        {
            //两阶段提交协议中的准备阶段
            Console.WriteLine("准备提交");
            ConsoleKeyInfo key = Console.ReadKey();
            if (key.KeyChar == 'Y' || key.KeyChar == 'y')
            {
                preparingEnlistment.Prepared();  //投票提交事务
            }
            else if (key.KeyChar == 'N' || key.KeyChar == 'n')
            {
                Console.WriteLine("\n由我投票整个事务回滚:" + _rollbackfrontvalue);
                (copy as IResourceCopy<T>).Copy(_commitfrontvalue, _rollbackfrontvalue);//回滚事务自愿
                preparingEnlistment.ForceRollback();//投票回滚事务,资源管理发生错误时因该将其自动回复数据,
                //因为事务管理不会通知发生ForceRollback()方法的管理器。
            }
        }
        public void Commit(Enlistment enlistment)
        {
            //尝试提交
            Console.WriteLine("事务尝试提交");
            enlistment.Done();//通知事务管理器,参与者已完成提交工作。
        }
        public void Rollback(Enlistment enlistment)
        {
            //事务激活阶段处理错误,执行回滚
            Console.WriteLine("操作失败,回滚" + _rollbackfrontvalue);
            (copy as IResourceCopy<T>).Copy(_commitfrontvalue, _rollbackfrontvalue);//回滚事务自愿
            enlistment.Done();
        }
        public void InDoubt(Enlistment enlistment)
        {
            //与其他的资源管理器失去联系
            Console.WriteLine("与其他的资源管理器失去联系,通常记录日志");
            enlistment.Done();
        }
        #endregion
    }

 

该类是支持两阶段提交协议的资源管理器,由于不同的资源面临这不同的数据复制操作。当我们进行初始数据备份的时候需要对不同的数据类型进行不同的数据复制操作,所以我们需要一个规范来进行约定。

代码2:资源复制接口

/// <summary>
    /// 事务性资源管理器中的资源拷贝,不同的资源类型存在多种拷贝形式。
    /// </summary>
    public interface IResourceCopy<T>
    {
        void Copy(T t1, T t2);
}

 

代码3:实现StringBuilder类型的数据复制

/// <summary>
    /// StringBuilder类型的数据Copy对象,需要实现IResourceCopy泛型接口。
    /// </summary>
    public class StringBuilderCopy : IResourceCopy<StringBuilder>
    {

        #region IResourceCopy<StringBuilder> 成员

        public void Copy(StringBuilder t1, StringBuilder t2)
        {
            t1.Remove(0, t1.Length);
            t1.Append(t2.ToString());
        }

        #endregion
}

 

这样我们就有了对于StringBuilder类型的数据复制操作类。

代码4:将自定义的资源管理器参与到事务处理中

/// <summary>
    /// 事务范围内的登记资源管理对象的状态
    /// </summary>
    public class EnlistmentDemo
    {
        [MethodImpl(MethodImplOptions.Synchronized)]//锁住当前方法,避免多线程访问破坏事务资源的一致性。
        public void Start()
        {
            //易失性资源
            StringBuilder stringvalues = new StringBuilder("123");
            StringBuilder stringvalues2 = new StringBuilder("456");
            StringBuilder stringvalues3 = new StringBuilder("789");
            StringBuilder stringvalues4 = new StringBuilder("101112");
            //使用资源管理器进行管理
            IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy> resource =
                new IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy>(stringvalues, new StringBuilderCopy());
            IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy> resource2 =
                 new IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy>(stringvalues2, new StringBuilderCopy());
            IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy> resource3 =
                new IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy>(stringvalues3, new StringBuilderCopy());
            IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy> resource4 =
                 new IEnlistmentNotificationDemo<StringBuilder, StringBuilderCopy>(stringvalues4, new StringBuilderCopy());
            try
            {
                using (TransactionScope transcope = new TransactionScope())
                {
                    Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(commitran_TransactionCompleted);
                    //登记事务资源管理器,在开始一切事务性操作之前必须先登记资源管理器
                    Transaction.Current.EnlistVolatile(resource, EnlistmentOptions.None);
                    Transaction.Current.EnlistVolatile(resource2, EnlistmentOptions.None);
                    Transaction.Current.EnlistVolatile(resource3, EnlistmentOptions.None);
                    Transaction.Current.EnlistVolatile(resource4, EnlistmentOptions.None);
                    //开始事务性操作,该阶段属于事务的激活阶段。
                    stringvalues.Append("456");
                    stringvalues2.Append("789");
                    stringvalues3.Append("101112");
                    stringvalues4.Append("131415");
                    transcope.Complete();//开始两阶段提交,该阶段属于事务的准备阶段。
                }
            }
            catch { Console.WriteLine("事务执行出错,执行回滚"); }

            //查看被事务性操作后的值
            Console.WriteLine("事务完成后的结果值:");
            Console.WriteLine(stringvalues + "|" + stringvalues2 + "|" + stringvalues3 + "|" + stringvalues4);
        }

        //事务结束时触发的事件方法,可以捕获事务执行结果。
        void commitran_TransactionCompleted(object sender, TransactionEventArgs e)
        {
            Console.WriteLine("transaction completed:");
            Console.WriteLine("ID:             {0}", e.Transaction.TransactionInformation.LocalIdentifier);
            Console.WriteLine("Distributed ID: {0}", e.Transaction.TransactionInformation.DistributedIdentifier);
            Console.WriteLine("Status:         {0}", e.Transaction.TransactionInformation.Status);
            Console.WriteLine("IsolationLevel: {0}", e.Transaction.IsolationLevel);
        }
    }

 

我们来看一下效果:

图1:事务提交

图2:事务回滚:

这样我们就能很好的将自定义的资源管理器参与到事务处理当中来,对于分布式的事务处理其实也是一样的,在事务的操作范围内首先进行资源管理器的登记才能使用。

事务处理是一个庞大的领域,我这里只是一个小小的应用。希望大家能用的着。[王清培版权所有,转载请给出署名]

 

时间: 2024-07-31 20:04:39

.NET简谈自定义事务资源管理器的相关文章

使用KTM(内核事务管理器)进行文件事务处理

在本人最近的几篇关于事务处理的文章中,从事务处理的整体概念到具体的C#代码的实践操作基本上都已经能满足日常的开发需求.文章中大部分的事务范围类的操作都是局限于数据库,在本人的".NET简谈自定义事务资源管理器 "一文中我虽然实现了一个简单的自定义资源管理器,其实也能满足基本的项目需求,核心功能也实现了,但是对于文件事务操作我们是力不从心的.[王清培版权所有,转载请给出署名] 从数据库到自定义资源管理器都能参与到事务处理中来,在必要的时候保证数据的完整性,那么我们缺一个类型的资源操作,当

Win8系统Ribbon界面资源管理器

当我们打开Win8系统中的资源管理器,会发现Win8资源管理器中引入了Ribbon界面工具栏,将用户常用到的功能用图标的方式直接展现出来,而不是隐藏在下拉菜单中,方 便用户的操作.部分用户表示喜欢Ribbon界面,方便获取更多功能和快速操作;也有一些用户表示Ribbon界面占据窗口面积较大不太习惯,微软贴心地在Win8消费者预览中默认将"Ribbon"界面隐藏起来.我们也可以点击Ribbon工具栏右上角的箭头小按钮灵活收缩和展开Ribbon工具栏. 当 Win8资源管理器的Ribbon

win7下资源管理器快捷键Win+E失效解决方法

今天小编Windows 7 下突然发现快捷键 Win+E 打不开资源管理器了,真是太不方便了,为这点小事重装系统也太麻烦了,研究了一下,终于找到了解决方法: 在开始搜索栏中键入regedit.exe,回车,打开注册表编辑器. 若有用户账户控制窗口弹出,请允许以继续. 找到注册表项:HKEY_CLASSES_ROOTFoldershellexplorecommand. 在右边细节窗口中,找到值 DelegateExecute,并双击打开.(注册表修改不当会引起严重问题,建议先对此项做好备份再修改)

Windows 7资源管理器失忆操作技巧

  不同的优化技巧和系统设置技巧,对不同的人有着不同的用处,很多人苦心想解决的问题可能有些朋友压根没用.例如隐私保护,很多朋友电脑就一人用,是很少考虑此类情况的.今天要谈的Windows7资源管理器的搜索历史记录问题,就是涉及到了用户的隐私.Windows7强大的搜索功能相当好用,不过麻烦的是所有的搜索历史记录都会出现在下拉列表框中,如果使用的是公用计算机,安全性和私密性就是一个问题了. 我们可以通过两个办法来解决,一个手动,一个是利用软件,注意,如果您的系统是Windows7家庭基础版,需要用

Windows7下快捷键Win+E打不开资源管理器了怎么办

  故障现象: Windows 7 下快捷键 Win+E 打不开资源管理器了 解决方案: 在开始搜索栏中键入regedit.exe,回车,打开注册表编辑器. 若有用户账户控制窗口弹出,请允许以继续. 找到注册表项:HKEY_CLASSES_ROOTFoldershellexplorecommand. 在右边细节窗口中,找到值 DelegateExecute,并双击打开.(注册表修改不当会引起严重问题,建议先对此项做好备份再修改) 查一下 DelegateExecute 数值数据栏中的内容是否为

windows7中Win+E 打不开资源管理器怎么办

在开始搜索栏中键入regedit.exe,回车,打开注册表编辑器. 收起这个图片展开这个图片   若有用户账户控制窗口弹出,请允许以继续. 收起这个图片展开这个图片   找到注册表项:HKEY_CLASSES_ROOTFoldershellexplorecommand. 在右边细节窗口中,找到值 DelegateExecute,并双击打开.(注册表修改不当会引起严重问题,建议先对此项做好备份再修改) 收起这个图片展开这个图片   检查一下 DelegateExecute 数值数据栏中的内容是否为

.NET简谈事务、分布式事务处理

在本人的 " .NET简谈事务本质论"一文中我们从整体上了解了事务模型,在我们脑子里能有一个全局的事务处理结构,消除对数据库事务的依赖理解,重新认识事务编程模型. 今天这篇文章我们将使用.NET C#来进行事务性编程,从浅显.简单的本地事务开始,也就是我们用的最多的ADO.NET事务处理,然后我们逐渐扩大事务处理范围,包括对分布式事务处理的使用,多线程事务处理的使用.   数据库事务处理 数据库事务处理我们基本都很熟悉了,begin Transaction --end Transact

.NET简谈事务本质论

这篇文章主要介绍一下事务处理的本质. 其实事务处理对我们来说并不陌生,但是很多人对事务处理的理解似乎有点弄不清,觉得事务处理只存在于数据库中.导致这样的结果是有原因的,当我们开始准备学习编程的时候,都是从某些编程语言开始学起,而不像人家的国外会先从概念.原理.模型开始学习,所以我们都会将某些技术与一些语言.平台联系在一起,导致我们学习其他的语言或者平台会很吃力. 在学校里也好还是自学也好,为了很快的上手都会去学习一些工具然后才会慢慢的去学习跟我们日常开发有关系的技术,仅仅是技术实现而不会去追根究

win10安装(启动) .net framework 3.5组件出错:指定资源管理器中的事务支持未启动或已关闭

问题描述 看网上说的很多方法都试过了,1:使用命令提示符(错误6801,指定资源管理器中的事物支持未启动或以关闭)2:下载安装(错误同上)3:在windows中启动(错误同上)问题就是以上的这些,请大神帮我解答一下 解决方案 解决方案二:人在哪里?人在哪里解决方案三:人在哪里啊,大神在哪里