go4it

just do it

JdonFramework的缓存设计

JdonFramework的缓存设计

内嵌对象(Embedded Object)缓存设计

请看下面这段代码:

public class Category extends Model{

String Id;

Product product; //内嵌包含了一个Product对象

}

Category这个Model内嵌了Product这个Model,属于一种关联关系。

目前Jdon框架提供的缺省缓存是扁平式,不是嵌入式或树形的(当然也可以使用JbossCache等树形缓存替代),因此,一个ModelB对象(如Product)被嵌入到另外一个ModelA对象(如Category)中,那么这个ModelB对象随着ModelA对象被Jdon框架一起缓存。

假设实现ModelA已经在缓存中,如果客户端从缓存直接获取ModelB,缓存由于不知道ModelB被缓存到ModelA中(EJB3实体Bean中是通过Annotation标注字段),那么缓存可能告知客户端没有ModelB缓存。那么有可能客户端会再向缓存中加一个新的ModelB,这样同一个ID可能有两份ModelB,当客户端直接调用的ModelB进行其中字段更新,那么包含在ModelA中的ModelB可能未被更新(因为ModelA没有字段更新)。

有两种解决方案:

第一.最直接方式,通过手工清除ModelA缓存方式来更新,或者耐心等待ModelA缓存自动更新。手工清除缓存见下章。

注意:下面这种做法将也会导致不一致现象发生:

在DAO层读取数据库。生成ModelA时,直接读取数据库将ModelB充填。

第二.在进行ModelA和ModelB的相关操作服务设计时,就要注意保证这两种情况下ModelB指向的都是同一个。如下图:

clip_image002

为达到这个目的,只要在Service层和Dao层之间加一个缓存Decorator,服务层向Dao层调用的任何Model对象都首先经过缓存检查,缓存中保存的ModelA中的ModelB是一个只有ModelB主键的空对象,在服务层getModelA方法中,再对ModelA的ModelB进行充实,填满,根据ModelA中的ModelB的主键,首先再到缓存查询,如果有,则将缓存中ModelB充填到ModelA的ModelB中,这样上图目的就可以实现了。

相关实现可参考JiveJdon 3.0的代码,Forum/ForumMessage都属于这种情况。

Model缓存使用

Jdon框架通过两种方式使用Model缓存:

CRUD框架内部使用,如果你使用Jdon框架提供的CRUD功能,那么其已经内置Model缓存,而且会即时清除缓存。

通过CacheInterceptor缓存拦截器,如果你不使用Jdon框架的CRUD功能,缓存拦截器功能将激活,在向Service获取Model之前,首先查询当前缓存器中是否存在该Model,如果有从缓存中获取。当你的Model中数值更改后,必须注意自己需要手工清除该Model缓存,清除方法如下介绍。

Jdon框架除了提供单个Model缓存外,还在持久层Dao层提供了查询条件的缓存,例如如果你是根据某个字段按照如何排列等条件进行查询,这个查询条件将被缓存,这样,下次如果有相同查询条件,该查询条件将被提出,与其相关的满足查询条件一些结果(如符合条件总数等)也将被从缓存中提出,节省翻阅数据库的性能开销。

手工访问缓存

在一般情况下,前台表现层通过getService方法访问服务层一个服务,然后通过该服务Service获得一个Model,这种情况Jdon框架的缓存拦截器将自动首先从缓存读取。

但是,有时我们在服务层编码时,需要获得一个Model,在这种情况下,Jdon框架的缓存拦截器就不起作用,这时可能我们需要手工访问缓存。

因为所有服务类POJO都属于Jdon框架的容器内部组件,这实际是在容器内访问容器组件的问题。

使用com.jdon.container.finder. ContainerCallback,同时,该服务POJO类以ContainerCallback作为构造参数,当该POJO服务类注册到容器中时,容器的Ioc特性将会找到事先以及注册的ContainerCallback类。

通过ContainerCallback获得ContainerWrapper容器实例,然后通过ContainerWrapper下面方法:

public Object lookup(String name);

从容器中获得container.xml中注册的组件实例,这种方法每次调用获得的是同一个实例,相当于单例方式获得。

ModelManager modelManager =

(ModelManager)containerWrapper. lookup (“modelManager”);

其中“modelManager”字符串名称是从Jdon框架的jdonFramework.jar包中META-INF的container.xml中查询获知的。

获得ModelManager后,我们基本可以访问Model有关的功能安排,如ModelManager的getCache方法。

下节的手工清除缓存中,我们是通过WebAppUtil.getComponentInstance获得ModelManager实例,这是一种从容器外获得容器组件的方式,本节介绍从容器内获得容器组件的方式,这两种方式可根据我们实际需要灵活使用,关键是弄清除你需要在哪里触发组件调用?

手工清除缓存

注意:手工清除缓存不是必要的,因为缓存中对象是有存在周期的,这在Cache.xml中设置的,过一段时间缓存将自动清除那些超过配置时间不用的对象,这样你修改的数据将被从数据库重新加载。如果你等不及这些内在变化,可以手工处理:

有两种情况需要手工清除缓存,首先,在持久层的Dao类中,总是需要手工清除查询条件的缓存,只要在相应的增删改方法中调用PageIteratorSolver的clearCache方法既可。

如果你不实行这种缓存清除,那么你更改一个Model数据或新增一个新的Model数据,你在批量查询时,将看不到任何变化:Model数据没有被修改;新的Model没有出现在查询页面中。

其次,单个Model缓存在不使用Jdon框架的CRUD功能下也必须手工清除,如果你使用1.2.3以后版本,可以调用com.jdon.strutsutil.util. ModelUtil类的clearModelCache方法,该方法一般是Action中调用后台增删改服务之前被激活调用:

注意,手工清除Model缓存代码关键是:

modelManager.removeCache(keyValue);

keyValue是Model的主键值,例如User的主键userId值是”2356”,那么keyValue就是”2356”。简化代码如下:

//获得ModelManager实例

ModelManager modelManager = (ModelManager)
WebAppUtil.getComponentInstance(ComponentKeys.MODEL_MANAGER, request);

modelManager.removeCache(keyValue);

上面代码是在容器外访问获得ModelManager,使用上节容器内访问组件方式也可以获得ModelManager;前者适合在表现层使用;后者适合在服务层使用。

最后,介绍一下清除全部缓存的方式,调用ModelManager的clearCache方法(Jdon框架1.3以上版本),这样实际上将整个Jdon框架缓存全部清零。

前面两种清除缓存方式前提是首先获得ModelManager,特别是服务层需要清除缓存时,需要以容器内访问组件方式获得ModelManager,这只适合POJOService构成的服务层,如果我们使用EJB的Session Bean作为服务层实现,这时当前版本的Jdon框架容器不会在EJB容器中加载,因此,在Session Bean中无法访问到容器,无法获得ModelManager了,在这种情况下,可以通过设置Model的setModified属性为True,表示该Model已经修改更新,这样当表现层获取该Model时,Jdon框架缓存拦截器拦截时,发现该Model已经被修改,也就不会从缓存中获取。

Model还有另外一个方法setCacheble,当设置为false时,该Model将不会被保存到缓存中。如果你不希望某个Model被框架自动存入缓存,那么使用此功能,setCacheble和setModified区别是,前者一旦设置为真,相当于缓存失效,以后再也不能用缓存;而后者则是当前Model表示被修改过,这样当有任何再次(限一次)试图从缓存中读取这个Model时,都被会阻挡,从而可直接从数据库获得,然后再保存到缓存中,这样缓存中的Model数据就是新鲜的了。

明白Jdon框架setModified这个神奇作用,当你设置一个Model的setModified为真,那么你再读取缓存时,Jdon框架内部将忽略你这个读取,返回一个null;这样你就根据返回是否为空,再从数据库直接获得,获得后,别忘记再保存到缓存中,已覆盖前次修改的旧数据,保证以后每次从缓存中读取的都是新鲜数据。

=总结如下:手工缓存清除共有两种方式:

直接操作缓存,从缓存中清除;

如果无法操作到缓存体系,那么设置Model的setModified。

posted on 2009-07-09 20:58  cxccbv  阅读(456)  评论(0)    收藏  举报

导航