• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
flashelf
博客园    首页    新随笔    联系   管理    订阅  订阅

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

.net 基础类库.实列.System.Transactions.自定义事物 (对新正加的事物类进行讲解) 涉及技术 自定义事物类,以及 System.Transactions 下的一些类库的使用  线程级别静态变量(这个子要在变量上加个 [ThreadStatic] 就可高定) 文件io访问(这个就不讲解了太没意识了MSDN说的很清楚)

.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里真得有可以支持事物的 文件读写类笔者没有发现,如果谁发现了记得通知一下啊...
posted @ 2006-10-10 00:15  曲滨*銘龘鶽  阅读(2527)  评论(7)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3