【IT168技术文档】
在forum.jsp中有一个ResultFilter类的实例resultFilter。它给出页面显示Thread的起始位置和数量,并作为参数传入forum.threads()中,用于构造相关的SQL语句。当调用forum.threads(filter)时,程序将生成的SQL语句传入到getThreadBlock()方法中得到一个threadID的块,也就是一组threadID。之所以要读threadID块,是因为显示论坛时并不是显示一条线索就行了,而是一下显示十几条。这样做可以避免反复读数据库,而且threadID不是thread对象,并不占太大空间。forum.jsp
<%
// ResultFilter结果过滤类
ResultFilter filter = new ResultFilter();
filter.setStartIndex(start);
filter.setNumResults(range);
//调用Dbforum的threads()方法,获得ForumThreadIterator对象实例
ForumThreadIterator threads = forum.threads(filter);
......
while (threads.hasNext()) ...{
//对thead进行遍历
ForumThread thread = (ForumThread)threads.next();
//得到thread的ID
long threadID = thread.getID();
//得到线索的根帖子rootMessage
ForumMessage rootMessage = thread.getRootMessage();
//得到帖子主题和作者等信息
String subject = rootMessage.getSubject();
User author = rootMessage.getUser();
......
}
%>
DbForum.java
public class DbForum implements Forum, Cacheable ...{
......
public ForumThreadIterator threads(ResultFilter resultFilter) ...{
//生成SQL语句
String query = getThreadListSQL(resultFilter, false);
//得到threadID块
long [] threadBlock = getThreadBlock(query.toString(),
resultFilter.getStartIndex());
......
//返回ForumThreadBlockIterator对象
return new ForumThreadBlockIterator(threadBlock, query.toString(),
startIndex, endIndex, this.id, factory);
}
protected long[] getThreadBlock(String query, int startIndex) ...{
int blockID = startIndex / THREAD_BLOCK_SIZE;
int blockStart = blockID * THREAD_BLOCK_SIZE;
String key = query + blockID;
//根据Key的值到缓存中取得ThreadID的数组
CacheableLongArray longArray =(CacheableLongArray)threadListCache.get(key);
//在缓存中则返回
if (longArray != null) ...{
long [] threads = longArray.getLongArray();
return threads;
}
// 否则到数据库中取ThreadID的块,以数组形式返回
else ...{
LongList threadsList = new LongList(THREAD_BLOCK_SIZE);
Connection con = null;
Statement stmt = null;
...数据库操作 ...
}
long [] threads = threadsList.toArray();
//将 ThreadID的块加入缓存
threadListCache.add(key, new CacheableLongArray(threads));
return threads;
}
......
}
应该说使用了块以后,减轻了数据库的访问量,因而论坛的效率有了很大的提高。不仅如此,Jive又把块放入了缓存中。在getThreadBlock()方法里,Jive用Cache类的实例对象threadListCache来缓存threadID块,而关键字就是SQL语句加上blockID。也就是说,只要SQL语句和blockID相同,就可以在缓存中取出相同的threadID块。当然,缓存中找不到,还是要到数据库中读出来加入缓存的,这样论坛的效率又得到了进一步的提升。
ForumThreadBlockIterator类继承自ForumThreadIterator抽象类,而ForumThreadIterator类又实现了Iterator接口,因此得到ForumThreadBlockIterator的实例对象threads后,就可以在用threads.next()方法对它进行编历了。ForumThreadBlockIterator类的功能就是逐个读取ThreadID,然后根据ThreadID返回Thread对象,由此上层访问接口就和中间层衔接起来了。
小结
Jive的缓存机制值得学习的地方有很多,比如读取线索时不是读一条而是读一个block;显示线索的起始位置和数量用专门的一个类来管理,并且动态生成SQL语句;用一个专门的类来负责管理缓存;把论坛缓存对象的功能抽象出来形成一个缓存的抽象类DatabaseCache,让它去跟低层数据结构联系起来等。这些都体现了面向对象的设计原则,即提高软件的可维护性和可复用性。
同时,Jive也告诉我们,要想编好程序,只懂条件语句和循环语句可不行,还要必须选择好的数据结构,掌握好的面向对象的设计原则,熟悉设计模式思想方法,这样才能编写出强壮、高效的代码。
