现在的位置: 首页 > 综合 > 正文

.net 基础类库.实列.System.Transactions.自定义事物 (对2.0 加的事物类进行讲解)

2012年02月19日 ⁄ 综合 ⁄ 共 8480字 ⁄ 字号 评论关闭
文章目录

.net 基础类库.实列.System.Transactions.自定义事物 (对新正加的事物类进行讲解)

涉及技术
自定义事物类,以及 System.Transactions 下的一些类库的使用
线程级别静态变量(这个子要在变量上加个 [ThreadStatic] 就可高定)
文件io访问(这个就不讲解了太没意识了MSDN说的很清楚)
 上篇文章 “状态机工作流.实列.报销审批流程(三) ” 发表之后发现IPendingWork 接口会传入一个 System.Transactions.Transaction 对象于是产生了兴趣研究了2个小时
写了一个小程序和大家分享一下成果 2006-10-09 23:28

   可能很多人已经知道很多数据库操作对象都已经支持 “事物性代码”如果不知道去看看 TransactionScope 类的msdn的帮助去,难道只有数据库对象会自动支持这种事物吗?
那当然是不可能的,不过作者找了半天也没有发现那个类的帮助上写了会支持“事物性代码”、子找到如下字样
   System.Transactions
基础结构通过支持在 SQL Server、ADO.NET、MSMQ 和 Microsoft 分布式事务协调器 (MSDTC) 中启动的事务,使事务编程在整个平台上变得简单和高效、看来没别的对象了。

  自己能做一个吗?答案是肯定的,继续搜寻MSDN 发现一个 IEnlistmentNotification 接口子要实现他,在用 Transaction.Current.EnlistVolatile 登记一下就应该好使了, MSDN上有一个简单的列子在 IEnlistmentNotification 接口的下面,不过那个列子太简单了几乎是简单到啥用都没有的地步了

  还是自己给自己搞个需求吧要不没法做的!
需求如下

    要做一个多文件读写删除,保存如果失败就回滚的例子

  1. 在多个函数里写不同的文件最后回滚
  2. 适合在ASP.net那种多线程访问的情况下使用没有问题

哎文件 io里的那些流都不支持 这个郁闷还真得好好设计一下,怎么自持多个文件的回滚那当然是放到列表里的了!怎么在多个函数里都可以使用哪?只能提供一个单列的对象了看来
,不过存静态的单列有线程问题,不能用哎!.
对了用那个 [ThreadStatic] 标签,这个标签我用了好久很爽尤其在Web那种多线程可能并发的情况下...
可以了啥都不缺了开始做吧

[程序下载 / download],是一个命令行程序演示没图

类设计/使用方法说明

  1. transFileModel

        /// <summary>
        
    /// 文件路经模块类,用于保存一些路径信息
        
    /// </summary>
        internal class transFileModel
        {
            
    //备份文件目录
            public string BakFileDir = string.Empty;
            
    //文件全路径
            public string FileAllPath = string.Empty;
            
    //备份全路径
            public string BakGuidAllPath = string.Empty;

        }

  2. ContextData

      

    /// <summary>
        
    /// 对象保存类,保存要进行事物处理的文件路经
        
    /// </summary>
        internal class ContextData
        {
            
    public static object _olock = new object();
            
    /// <summary>
            
    /// 文件路径模块列表
            
    /// </summary>
            public List<transFileModel> FileList = new List<transFileModel>();

            static ContextData()
            {

            }

            /// <summary>
            
    /// 注意:线程级别静态变量,否则这个类会有线程冲突
            
    /// </summary>
            [ThreadStatic]
            
    public static ContextData staticData = new ContextData();
            
    /// <summary>
            
    /// 文件路径模块列表对应的属性
            
    /// </summary>
            public static List<transFileModel> BakList
            {
                
    get
                {
                    
    return staticData.FileList;
                }
            }
            
    /// <summary>
            
    /// 添加一个 文件到 BakList
            
    /// </summary>
            
    /// <param name="bakDir"></param>
            
    /// <param name="filePath"></param>
            public static void AddFile(string bakDir, string filePath)
            {

                bakDir = Path.GetFullPath(bakDir);
                filePath 
    = Path.GetFullPath(filePath);

                lock (_olock)
                {
    //安全起见还是 lock 一下
                    if (!Directory.Exists(bakDir))
                        Directory.CreateDirectory(bakDir);
                }

                string GuidFileName = string.Empty;
                
    string bakGuidAllPath = string.Empty;

                if (File.Exists(filePath))
                {
    //文件如果存在就备份到备份目录,并已Guid.bak方式存储
                    GuidFileName = Guid.NewGuid().ToString() + ".bak";
                    bakGuidAllPath 
    = Path.Combine(bakDir, GuidFileName);

                    File.Copy(filePath, bakGuidAllPath, true);

                    Console.WriteLine("文件以成功copy");
                }

                transFileModel model = new transFileModel();
                model.BakFileDir 
    = bakDir;
                model.BakGuidAllPath 
    = bakGuidAllPath;
                model.FileAllPath 
    = filePath;

                staticData.FileList.Add(model);

            }

            public static void ClearFileList()
            {
                BakList.Clear();
            }

        }

  3. TransactionTools

        public class TransactionTools : System.Transactions.IEnlistmentNotification
        {
        
            
    #region IEnlistmentNotification 成员
            
            
    public static object _olock = new object();
            
            
    public TransactionTools()
            {
                
    if (Transaction.Current== null ) throw new ApplicationException("靠!没开事物那");
                Transaction.Current.EnlistVolatile(
    this,EnlistmentOptions.None);            
            }
            
            
    ~TransactionTools()
            {
                
            }

            public static void RegFile(string BakDir,string filePath)
            {
                ContextData.AddFile(BakDir,filePath);
            }
            
            
    public void Commit(System.Transactions.Enlistment enlistment)
            {
                Console.WriteLine(
    "通知登记的对象事务正在提交。:");    
                ContextData.ClearFileList();
                enlistment.Done();
                
            }

            public void InDoubt(System.Transactions.Enlistment enlistment)
            {
                Console.WriteLine(
    "通知登记的对象事务的状态不确定。:");    
                
    throw new Exception("The method or operation is not implemented.");
            }

            public void Prepare(System.Transactions.PreparingEnlistment preparingEnlistment)
            {
                
    //throw new Exception("The method or operation is not implemented.");
                
    //在这里应该判断,原始文件是否可写,备份文件是否可读
                Console.WriteLine("通知登记的对象事务正在为提交做准备。:");    
                preparingEnlistment.Prepared();
            }

            public void Rollback(System.Transactions.Enlistment enlistment)
            {
                Console.WriteLine(
    "通知登记的对象事务正在回滚。:");    
                List
    <transFileModel> transLsit = ContextData.BakList;
                
    if(transLsit.Count > 0)
                {
                    
                    
    foreach(transFileModel mod in transLsit)
                    {
                        
                        
    if(mod.BakGuidAllPath.Length == 0 && File.Exists(mod.FileAllPath))
                        {
    //文件是新建立的,而且存在的话删除
                            Console.WriteLine("正在回滚删除文件:", mod.FileAllPath);
                            File.Delete(mod.FileAllPath);
                        }
                        
    else if(mod.BakGuidAllPath.Length != 0)
                        {
    //文件有bak路径证明,他不是新建了的需要回滚
                            Console.WriteLine("正在会滚文件:", mod.FileAllPath);    
                            File.Copy(mod.BakGuidAllPath,mod.FileAllPath,
    true);
                            File.Delete(mod.BakGuidAllPath);
                        }
                        
                    }
                }

                ContextData.ClearFileList();
                enlistment.Done();
            }

            #endregion
            
        }

  4. 使用演示
    static class Program
        {
            
    static readonly string BakPath = Path.Combine(Application.StartupPath, "Bak");
            
            
    //测试函数一
            static void writerFile1()
            {
                
    string fpath = Path.Combine(Application.StartupPath, "a.txt");
                TransactionTools.RegFile(BakPath, fpath);

                using (StreamWriter sw = new StreamWriter(fpath, true))
                {
                    Console.WriteLine(
    "正写入:{0}", fpath);
                    
                    sw.WriteLine(
    "A:{0:yyyy-MM-dd HH:mm:ss.ffff}",DateTime.Now);
                    
                }
                
                
                
            }
            
            
    //测试函数二
            static void writerFile2()
            {
                
    string fpath = Path.Combine(Application.StartupPath, "b.txt");
                
                TransactionTools.RegFile(BakPath, fpath);
                    
                
    using (StreamWriter sw = new StreamWriter(fpath , true))
                {
                    Console.WriteLine(
    "正写入:{0}",    fpath);    
                    sw.WriteLine(
    "B:{0:yyyy-MM-dd HH:mm:ss.ffff}", DateTime.Now);
                    
                }
                
            }
            
            
    static void DBUpdate1()
            {
    //数据库操作对象支持 事物性代码,起码,sqlserver 的一系列、对象支持这里我就不写更新数据库的了,自己加上吧
            
            }
            
    /// <summary>
            
    /// 应用程序的主入口点。
            
    /// </summary>
            [STAThread]
            
    static void Main()
            {

                
                using(TransactionScope ts = new System.Transactions.TransactionScope())
                {
                    Transaction.Current.TransactionCompleted
    +=new TransactionCompletedEventHandler(Current_TransactionCompleted);
                    TransactionTools tt 
    = new TransactionTools();
                        
                        
    //调用好多个函数有数据库的和文件的
                        
                        writerFile1();
                        writerFile2();
                        DBUpdate1();
                        
                        Console.Write(
    "输入[Y] 提交否则会滚");
                        
    char c = (char)Console.Read();
                        
                        
    if(c.ToString().ToUpper()=="Y")
                            ts.Complete();
                    
                    
                    
                }
                
                Console.Read();
                
    //Application.EnableVisualStyles();
                
    //Application.SetCompatibleTextRenderingDefault(false);
                
    //Application.Run(new Form1());
            }

            static void Current_TransactionCompleted(object sender, TransactionEventArgs e)
            {
                Console.WriteLine(
    "事物状态:{0}" , e.Transaction.TransactionInformation.Status);
                
    //throw new Exception("The method or operation is not implemented.");
            }
        }

最后

这个文档写的比较草、也许2.0里真得有可以支持事物的 文件读写类笔者没有发现,如果谁发现了记得通知一下啊...

抱歉!评论已关闭.