TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
关于我的Scjp在线测试,小结一下。
数据库连接池我用的是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;
}
}
二、缓存管理器
我的缓存系统用的是开源的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+1;
* 再将数组中元素的值打乱,随机排列数据库中试题的ID号
* for(int i=0;i< count;i++){
* int j=(int)(Math.random()*count);
* int temp=a;
* a=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+1;//数据库中ID号是从1开始
for(int i=0;i< count;i++){ //将数组中元素的值打乱,随机排列数据库中试题的ID号
int j=(int)(Math.random()*count);
int temp=a;
a=a[j];
a[j]=temp;
}
for(int i=0;i<300;i++){
rs = stmt.executeQuery("select * from examination3 where id="+a);
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的试题,则交换a与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;
a=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);
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;
}
}
[/code] 三、JSP页面
<%@ page contentType="text/HTML;charset=gb2312" %>
<%@ page language="java"%>
<%@page import="com.java3z.data.*" %>
<%
ScjpVObjManager cache = ScjpVObjManager.getInstance();
int a[]=new int[300];
for(int i=0;i<300;i++)
a=i; for(int i=0;i<300;i++){ //将内存缓存中的试题找乱
int j=(int)(Math.random()*300);
int temp=a;
a=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+"<br>");
}
%>
四、如有不当之处,敬请各位指正。 |
|