数据库连接池我用的是proxool。
再看看我的缓存策略:假设数据库中有1000道题,先一次性从数据库中随机读取300道题放入内存中缓存,当某试题缓存过期时则从余下的700道题中随机取一试题取代过期的试题。JSP出题页面则从内存缓存中的300题中随机取60题。这样充分考虑了页面的响应速度,用户不会因为出题网页反应迟缓而抱怨或离去。
而且网上参加测试的人越多,速度也不会有影响,因为没有过期的试题,也就不用访问数据库,试题全部从内存缓存中取出。
具体实现如下,供参考。
一、值对象 ScjpVObj类中的字段与数据库中试题表的字段对应 package com.java3z.data; import java.io.Serializable; import java.util.Date; public class ScjpVObj implements Serializable { int id = 0; String content;//试题的内容 String option;//试题选项的个数 String explain;//答案的点评 int test_type;//试题的类型,单选:0 多选:1 String answer;//试题的答案 int score;//试题的分数 Date qdate;//试题的添加时期 public ScjpVObj() { } public ScjpVObj(int id,String content,String option,String explain,int test_type,String answer,int score,Date qdate){ this.id=id; this.content=content; this.option=option; this.explain=explain; this.test_type=test_type; this.answer=answer; this.score=score; this.qdate=qdate; } public int getId(){ return id; } public String getcontent(){ return content; } public void setcontent(String content){ this.content=content; } public String getoption(){ return option; } public void setoption(String option){ this.option=option; } public String getExplain(){ return explain; } public void setExplain(String explain){ this.explain=explain; } public int getTest_type(){ return test_type; } public void setTest_type(int test_type){ this.test_type=test_type; } public String getAnswer(){ return answer; } public void setAnswer(String answer){ this.answer=answer; } public int getScore(){ return score; } public void setScore(int content){ this.score=score; } public Date getQdate(){ return qdate; } public void setQdata(Date qdate){ this.qdate=qdate; } } 二、缓存管理器三、JSP页面
我的缓存系统用的是开源的JCS。 package com.java3z.data; import java.sql.*; import org.apache.jcs.JCS; import org.apache.jcs.engine.behavior.IElementAttributes;
/** 说明:设数据库中有count个题可用,试题ID号一定要连续,用数组a保存试题的ID号, * for(int i=0;i< count;i++) * a[i]=i+1; * 再将数组中元素的值打乱,随机排列数据库中试题的ID号 * for(int i=0;i< count;i++){ * int j=(int)(Math.random()*count); * int temp=a[i]; * a[i]=a[j]; * a[j]=temp; * } * 取前300个试题(试题ID为a[0]至a[299])放入缓存.如果某个试题id缓存过期,则从300个题后面 *(试题ID为a[300]至a[count-1])中取ID,替换过期的id和试题,这样可保证缓存中的试题不断更新。 */ public class ScjpVObjManager { private static ScjpVObjManager instance; private static JCS scjpCache; private static int a[];//保存数据库中所有试题的ID号 private static int count;//数据库中试题的数目 private ScjpVObjManager()//构造函数 { Statement stmt=null; Connection conn=null; ResultSet rs=null; ScjpVObj vobj=null; try { scjpCache = JCS.getInstance("scjpCache"); conn = DriverManager.getConnection("proxool.Access"); stmt = conn.createStatement(); rs=stmt.executeQuery("select count(*) from examination3"); rs.next(); count=rs.getInt(1); //获取数据库中试题的数目 a=new int[count]; for(int i=0;i< count;i++) a[i]=i+1;//数据库中ID号是从1开始 for(int i=0;i< count;i++){ //将数组中元素的值打乱,随机排列数据库中试题的ID号 int j=(int)(Math.random()*count); int temp=a[i]; a[i]=a[j]; a[j]=temp; } for(int i=0;i<300;i++){ rs = stmt.executeQuery("select * from examination3 where id="+a[i]); while(rs.next()){ int id=rs.getInt("id"); String title=rs.getString("content"); String content=rs.getString("option"); String explain=rs.getString("explain"); int test_type=rs.getInt("test_type"); String answer=rs.getString("answer"); int score=rs.getInt("score"); Date qdate=rs.getDate("qdate"); vobj=new ScjpVObj(id,content,option,explain,test_type,answer,score,qdate); scjpCache.put("ScjpVObj" + i, vobj);//将试题放入内存中缓存 } } }catch(SQLException e){ System.err.println(e.getMessage()); }catch(Exception e){ System.err.println(e.getMessage()); }finally{ try{ stmt.close(); conn.close(); } catch(SQLException ex1){ System.out.print(ex1); } } } /** * Singleton access point to the manager. */ public static ScjpVObjManager getInstance() { synchronized (ScjpVObjManager.class) { if (instance == null) { instance = new ScjpVObjManager(); } } return instance; } /** * Retrieves a ScjpVObj. Default to look in the cache. */ public ScjpVObj getScjpVObj(int id) { return getScjpVObj(id, true); } public ScjpVObj getScjpVObj(int i, boolean fromCache)//id必须在0<=id<=299 { if(i<0||i>299) return null;//简单的处理 ScjpVObj vobj = null; // First, if requested, attempt to load from cache if (fromCache) { vobj = (ScjpVObj) scjpCache.get("ScjpVObj" + i); } // 如果内存缓存中没有试题ID号为a[i]的试题,则交换a[i]与a[300],为了保证每次取题不一样,要保证a[300]是随机的。 if (vobj == null){ for(int k=300;k< 305;k++){ //打乱五个元素的顺序,题库中试题至少要有305个 int j=(int)(300+(int)(Math.random()*(count-301))); int temp=a[k]; a[k]=a[j]; a[j]=temp; } int t=a[i]; a[i]=a[300]; a[300]=t; vobj = loadScjpVObj(i);//从数据库中取题 } return vobj; } public ScjpVObj loadScjpVObj(int i) { ScjpVObj vobj=null; Statement stmt=null; Connection conn=null; try{ conn = DriverManager.getConnection("proxool.Access"); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from examination3 where id="+a[i]); while(rs.next()){ int id=rs.getInt("id"); String title=rs.getString("content"); String content=rs.getString("option"); String explain=rs.getString("explain"); int test_type=rs.getInt("test_type"); String answer=rs.getString("answer"); int score=rs.getInt("score"); Date qdate=rs.getDate("qdate"); vobj=new ScjpVObj(id,title,content,explain,test_type,answer,score,qdate); if (vobj!=null){ scjpCache.put("ScjpVObj" + i, vobj);//缓存这个试题 } } }catch(SQLException e){ System.err.println(e.getMessage()); }catch (Exception e){ System.err.println(e.getMessage()); }finally{ try{ stmt.close(); conn.close(); } catch(SQLException ex1){ System.out.print(ex1); } } return vobj; } }
for(int i=0;i<300;i++){ //将内存缓存中的试题找乱
int j=(int)(Math.random()*300);
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
for(int count=0;count<60;count++){//出题60个
ScjpVObj bv=(ScjpVObj)cache.getScjpVObj(a[count],true);
String content=bv.getContent();
out.println(content+"
");
}
%>
四、如有不当之处,敬请各位指正。
↑返回目录
前一篇: jsp作图50例
后一篇: 抓HTTP头信息的工具ieHTTPHeader