自定义支持事务操作的资源管理器

(一)应用场景

在使用事务时,我们多是基于已经提供事务管理功能的资源管理器进行事务操作,比如各种数据库,这基本上能够满足需求,但是有些时候,我们需要对一些内存中的对象进行事务管理,如:在使用EF时,当事务回滚时,数据库中的数据会进行回滚,但是EF缓存中的数据仍会保持被修改后的状态,不会进行回滚,这样在一些特殊的应用下也许会产生错误。到目前为止,EF似乎还不支持二级缓存,但是网上已经流传出EF实现二级缓存的方法,我想,如果要实现EF的二级缓存,那必须要完成其对事务操作的处理了,类似的应用还有很多,不多说了,下面开始介绍如何自定义支持事务的资源管理器。

(二)实现

其实自定义这样的资源管理器还是比较方便的,以使用环境事务为例:继承自IEnlistmentNotification接口的类在注册之后就能得到事务提交或回顾的消息通知,IEnlistmentNotification接口包含了下面四个方法:Commit,InDoubt,Prepare,Rollback

在环境事务即将Commit时,会通知所有实现了IEnlistmentNotification接口的类,调用其Prepare方法进行准备,在所有类都报告准备完成后,环境事务会调用所有类的Commit方法进行事务提交,当所有类的提交都报告完成后,整个环境事务会提交完成,如果过程中任何一个类的任何一步报告了失败,整个事务将会终止。

环境事务将Rollback时也是一样,将会一次调用每个类的Rollback方法。

很容易想到,我们只要将开启事务之前的数据缓存起来,当commit时将在事务作用区间内更新的数据更新到缓存上,在rollback时将事务作用区间内更新的数据丢弃掉,应该就能基本实现需求了,当然,在进行数据缓存的过程中必须进行深表复制,对浅表信息(引用信息)进行缓存在本设计中是没有意义的。

 

实现代码如下:

缓存数据:其中ManageValue用于保存进入事务作用区域之前的数据信息,Flush_ManageValue用于保存在事务作用区域内更改的信息

        Dictionary<string, object> ManageValue = new Dictionary<string, object>();
Dictionary<string, object> Flush_ManageValue = new Dictionary<string, object>();

SetValue和GetValue是用户用于获得或设置数据的接口,他们都包含了对Transaction.Current的判断,用于判定是否是在事务作用域内执行

        public void SetValue(string name,object value)
{
if (Transaction.Current == null)
{
if (ManageValue.ContainsKey(name))
{
ManageValue[name] = DeepClone(value);
}
}
else
{
initManger();
if (Flush_ManageValue.ContainsKey(name))
{

Flush_ManageValue[name] = DeepClone(value);
}
}

}
public object GetValue(string name)
{
if (Transaction.Current == null)
{
return ManageValue[name];
}
else
{
initManger();
return Flush_ManageValue[name];
}
}

其中使用到的方法

initManger用于在第一次调用资源管理器时将实现IEnlistmentNotification接口的工具类注册到环境事务中,并将ManageValue中的数据深表复制到Flush_ManageValue中

DeepClone是一个深表复制方法,是使用序列化反序列化实现的,这也就要求使用这个资源管理器的对象必须是可序列化的

        private void initManger()
{
if (Transaction.Current != null)
{
if (enListment == null)
{
enListment = new ResouceManager2(this);
Transaction.Current.EnlistVolatile(enListment, EnlistmentOptions.None);
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler((object sender, TransactionEventArgs args) =>
{
Console.WriteLine("事务完成");

});

Flush_ManageValue = (Dictionary<string, object>)DeepClone(ManageValue);
}
}
}

private object DeepClone(object from)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, from);
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);//将读写其实位置重置到流的开头
return formatter.Deserialize(stream);
}
}

commit和Rollback方法是对缓存数据进行操作的具体实现(注意不是实现接口继承的方法)

        private void Commit()
{
this.ManageValue = Flush_ManageValue;
Flush_ManageValue = null;
}

private void RollBack()
{
Flush_ManageValue = null;
enListment = null;
}
ResouceManager2 类是继承IEnlistmentNotification接口的类,之所以将其定义在资源管理器类FlushManager2的内部主要是为了隐藏这FlushManager2类的一些方法
    partial class FlushManager2
{
class ResouceManager2 : IEnlistmentNotification
{
private FlushManager2 flushMag = null;

public ResouceManager2(FlushManager2 flush)
{
this.flushMag = flush;
}


#region IEnlistmentNotification 成员


public void Commit(Enlistment enlistment)
{
Console.WriteLine("commit");
if (flushMag != null)
{
flushMag.Commit();
}
enlistment.Done();
}

public void InDoubt(Enlistment enlistment)
{
Console.WriteLine("InDoubt");
enlistment.Done();
}


public void Prepare(PreparingEnlistment preparingEnlistment)
{

Console.WriteLine("Prepare");
preparingEnlistment.Prepared();
}

public void Rollback(Enlistment enlistment)
{
Console.WriteLine("rollback");

if (flushMag != null)
{
flushMag.RollBack();
}

enlistment.Done();
}
#endregion
}
}

之后就是用户调用的类了,我用int,string和自定义的Class进行了测试

                        int value1 = 1;
string value2 = "first";
Student stu = new Student();
stu.userid = "1234";
stu.username = "zhangsan";
FlushManager2 flushManager = new FlushManager2();
flushManager.AddManager("value1", value1);
flushManager.AddManager("value2", value2);
flushManager.AddManager("stu", stu);
using (TransactionScope scope = new TransactionScope())
{
flushManager.SetValue("value1", 3);
flushManager.SetValue("value2", "ls");
stu.username = "lisi";
stu.userid = "8888";
flushManager.SetValue("stu", stu);
flushManager.SetValue("value1", (object)9);
stu.username = "lisi";
stu.userid = "7777";
flushManager.SetValue("stu", stu);

Console.Write("commit?");
if (Console.ReadLine().Equals("y"))
{
scope.Complete();
}
}
Console.WriteLine("--lst--");
Console.WriteLine(flushManager.GetValue("value1").ToString());
Console.WriteLine(flushManager.GetValue("value2").ToString());
Console.WriteLine(flushManager.GetValue("stu").ToString());

最终的输出结果为






posted @ 2011-11-01 17:39  wangking1029  阅读(558)  评论(0编辑  收藏  举报