用了Hibernate,还需要再加一层Cache吗?

众所周知,CMPEntityBean不适合执行复杂的、大批量的查询,通常我们在项目中使用DAO模式实现这样的需求。持久层我们选择了Hibernate。现在我的问题是,Hibernate已经实现了Cache,它可以利用EhCache、OSCache之类的东东实现对pojos的缓存。但是我想利用JBossCache或OSCache再加一层Cache,用于直接缓存查询所得的List、Set,不知道是否多此一举?我参考了这篇文章,它说:“Using pure JDBC calls in a real world application is not recommended. Instead, object relational modeling (ORM) tools such as Hibernate or JDO and database connection pooling (Commons DBCP) frameworks should be considered for data access requirements.”我感到迷惘,Hibernate不是有Cache吗?
顺便提一下,我不打算用AspectJ。但是选择什么AOP框架呢,Spring不错,可惜不能单独抽取其AOP,不知道JBOSS AOP如何。另外,AOP的思想挺简单的,自己实现一个似乎也不是很困难的事情。
抉择ing。

>Hibernate不是有Cache吗
Hibernate的Cache是针对Model和数据访问目的优化的,这与CMP缓存优化目的是一样的,而且CMP的缓存优化走向极端,它是Pool+Cache,非常耗费内存,所以批量查询我们不推荐使用CMP。

Hibernate的缓存不能满足前台表现层批量查询的目的,所以还是必须靠近表现层存在一个Cache,Cache机制越靠近前台,性能越高。

至于批量查询Cache,如果我推荐,当然首选Jdon框架,其原理你可参考“Java实用系统开发指南”。你可以自己测试比较几个框架的批量查询性能。

另外敬请等待jdon 1.2,其AOP框架使用比较简单方便,虽然是一种粗粒度的拦截器,但是在实际应用中已经足够对付。Jdon 1.2在这个月内会推出,包括详细文档,已经基本成型,如果你要尝鲜,可直接联系我。

>至于批量查询Cache,如果我推荐,当然首选Jdon框架
批量查询框架我自己有,使用起来也很方便,可惜没有Cache(土!!!)。现在想利用AOP在现有代码不动的前提下加入Cache。我现在需要的是Cache的实现(选择了OSCache)和单纯的AOP框架。Spring融入了太多的东西,反而会使我的框架与其它实现耦合。所以现在正考虑使用JbossAOP或干脆自己做一个。如果banq的AOP可以抽取出来,那么也在选择范围之中。
另外,banq不会是自己实现的Cache吧,我曾经考虑过,发现很复杂。不过AOP的框架,如果搞一个简单的,相信没有问题。哪位如果有这方面的经验,希望不吝赐教。

你现在下载Jdon框架现在版本,只留下其中的AOP BusinessProxy controller包,其他都可以去掉,其中已经有CacheInterceptor。可直接使用,或者你自己参考自己做一个。

可以参考对象池的做法:
http://www.jdon.com/jive/article.jsp?forum=91&thread=18095

我的目的是完成一个项目中关于批量查询部分的重构,这个项目包括40多个查询,采用DAO模式,所有查询的实现都遵循共同的接口:


public interface DAOObject{
QueryResult query(QueryParameters params);
}

最初这样做是因为项目时间紧张,所以没有写特别复杂的设计(XP?)。现在我想加入缓存以提高性能。
由于都实现了DAOObject,所以实现查询结果的缓存而不修改现有代码是比较简单的。不需要AOP框架,因为所有AOP框架都融入了其他DD,Spring和AspectJ就别说了,Jdon也不是仅针对DAO的。BusinessProxy我用不到。QueryResult中包含着ValueObjects的集合或RowSet,我不知道缓存这样的对象是否可行。
banq的代码正在看,提些建议:既然在SourceForge发布,就应该多写点javadoc,并且用英文。很多没有完成的就别发布了,另外,异常处理也需要完善,catch(Exception e){}是不行地。

DAO是一个普通POJO,基本AOP可以实现POJo拦截。

知道你在研究Jdon,赶忙将1.2版发给你,我还有最后API注释写一下就正式发布了,供你研究,也在1.2版本出面前多提宝贵意见,省得发生前面版本的仓促。

有什么建议我们交流,也许可就你这个案例探讨出一个合适的解决方案。

收到了,正在看,目前感觉比较晕-_-

哈,你都感觉晕,一般人不容易看懂,希望你能成为知音,这东西也是我自己用着,快速开发一些项目。1.2版本我将版权改为程序作者自己,而一定是jdon.com,这是以前一个疏忽,如果你有时间能一起完善,真是万幸。

通过开源,确实做得比以前要做得好得多,但是也费时间和精力。

哦,使用Eclipse可以打开,我正在写核心设计原理,这章写好,估计对理解框架有好处,给你的只是如何应用,下次我要把Spring的那个Jpetstore用Struts+Jdon+Hibernate改写成一个演示源码,希望对于应用者有用。

>下次我要把Spring的那个Jpetstore用Struts+Jdon+Hibernate改写成一个演示源码,希望对于应用者有用
期待ing
我是用JBX打开的,加一个struts.jar和commons-beanutils.jar就通过了。

先解决我自己的问题吧,原理其实很简单,关键是在实际项目开发中如何适应工期的要求。原来的实现是这样的:


//所有DAO都必须实现这个接口,在其中加工原始查询参数,并利用
//SQLBuilder创建SQL Statement,执行,然后返回用QueryResult封装
//的结果,结果可以是ValueObject(s)也可以是RowSet
public interface DAOObject{
/**
执行批量查询
QueryParams params 包含查询参数和分页数据
SQLBuiler sqlBuilder SQLBuiler接口的事例――如何创建SQL
*/

QueryResult query(QueryParams params,SQLBuiler sqlBuilder);
}
//客户端这样调用
QueryFactory factory = QueryFactory.newInstance(
"myquery");
//准备参数...
//执行查询
QueryResult qr = factory.getQuery().query(params,mySQLBuilder);

特别简陋的实现,但是当时没有时间做更好的。现在我们在不改变那40多个DAO模块的前提下加入对QueryResult的缓存。

public class CachedDAOQuery implements DAOQuery{
protected DAOQuery realQuery;
public CachedDAOQuery
QueryResult query(QueryParams params,SQLBuiler sqlBuilder){
Key key = KeyMaker.makeKey(params);//利用params生成Key
//以下是伪代码
Cache cache = CacheProviderFactory.createCacheProvider().getCache();
if(cache contains key){
return cache.get(key);
}
else{
QueryResult qr = realQuery.query(params,SQLBuilder);
cache.set(qr);
return qr;
}
}
}
//工厂类也需要修改,它必须保证所有对实际DAOQuery的调用都必须经过
CachedDAOQuery这一关,代码略。

好了,上面用最简单的代理模式解决了我的问题,需要注意的是Cache的选择,不能用简单的Map,必须使用OSCache等产品。
这样重构就完成了。我现在不确定将RowSet缓存起来是否可行,幸好我们多数程序员采用的都是ValueObject(s)。

然后就是回归测试和性能测试,如果没有问题,我们就形成一个little release发布。

下一步重构是将所有的DAO(pojo)和业务模块结合在一起,形成完整的Facade层。这篇文章提供了不错的思路:
通用查询对象最优经验

再下一步的重构...,我需要一个NB的TagLib,不但能够动态显示QueryResult的内容,而且可以在客户端排序,就像windows的ListView控件,这需要javascript的帮助,更好的情况是,不但能够显示,而且可以编辑(满足批量修改和删除的需要)。

至于整个项目的重构我会参考banq的框架,现在对EJB提供支持的框架太少了,都是POJO!

代码写错了,我不是粘贴的(-_-)


public class CachedDAOObject implements DAOObject{
protected DAOOjbect realDAO;
public CachedDAOQuery(DAOObject dao) {
this.realDAO = dao;
}
//所有DAOQuery都改为DAOObject