📄 doccachemgr.java
字号:
package cn.js.fan.module.cms;
import org.apache.log4j.Logger;
import cn.js.fan.cache.jcs.*;
import cn.js.fan.db.Conn;
import java.util.Vector;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.js.fan.web.Global;
import cn.js.fan.db.SQLFilter;
import cn.js.fan.security.SecurityUtil;
/**
* 有三个缓存与Document关联,一个是用于Iterator模式列表的DOCBLOCKCACHEPRIX,另一个是Document本身的,还有一个是用于计算count值的COUNT_GROUP_NAME
* 当creat时,需更新组DOCBLOCKCACHEPRIX COUNT_GROUP_NAME ALL
* 当del时,需更新组DOCBLOCKCACHEPRIX COUNT_GROUP_NAME ALL
* 当update时,需更新cachePrix+id
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2004</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class DocCacheMgr implements ICacheMgr {
public static final int DOC_BLOCK_SIZE = 100;
private static final long[] EMPTY_BLOCK = new long[0];
public final static String FULLTEXT = "FULLTEXT"; // 用于全文检索,使用SQLServer的全文检索
public final static String ALL = "ALL"; // 用于搜索,使用like %...%
String COUNT_GROUP_NAME = "SQL_COUNT_";
String DOCBLOCKCACHEPRIX = "DOCBLOCK_";
String cachePrix = "doc";
public final static String CHILDREN_OF_PARENT = "CHILDREN_"; // 用于在首页列表显示一个目录下所有子目录中的文章,这种方法不能包含该目录下的文章,只能是子目录中的文章
public static long FULLTEXTMAXLIFE = 60; // 60分钟
static {
Config cfg = new Config();
FULLTEXTMAXLIFE = cfg.getIntProperty("cms.refresh_doc_relate_interval");
}
private long curFulltextLife = FULLTEXTMAXLIFE; // one hour
static boolean isRegisted = false;
Logger logger = Logger.getLogger(DocCacheMgr.class.getName());
RMCache rmCache = RMCache.getInstance();
String connname = "";
public DocCacheMgr() {
connname = Global.defaultDB;
if (connname.equals(""))
logger.info("DocCacheMgr:conname cann't be empty.");
regist();
}
/**
*
* @param code String
*/
public void refreshFulltext() {
try {
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + FULLTEXT);
}
catch (Exception e){
logger.error(e.getMessage());
}
}
/**
* 定时刷新缓存
*/
public void timer() {
// 刷新全文检索
curFulltextLife--;
if (curFulltextLife<=0) {
refreshFulltext();
curFulltextLife = FULLTEXTMAXLIFE;
}
}
/**
* regist in RMCache
*/
public void regist() {
if (!isRegisted) {
rmCache.regist(this);
isRegisted = true;
}
}
public void refreshCreate(String dir_code, String parent_code) {
//清DOCBLOCKCACHEPRIX缓存
try {
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + dir_code);
rmCache.invalidateGroup(COUNT_GROUP_NAME);
rmCache.invalidateGroup(ALL);
// 刷新其父目录的所有文章的列表缓存(不包含父目录本身)
// logger.info("refreshCreate:" + DOCBLOCKCACHEPRIX + CHILDREN_OF_PARENT + parent_code);
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + CHILDREN_OF_PARENT + parent_code);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void refreshUpdate(int id) {
removeFromCache(id);
}
/**
* 当更新文章时,如果examne被改变时,则需用此函数更新缓存
* @param id int
* @param dir_code String
* @param parent_code String
*/
public void refreshUpdate(int id, String dir_code, String parent_code) {
// 更新缓存
removeFromCache(id);
// 清组DOCBLOCKCACHEPRIX缓存
try {
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + dir_code);
rmCache.invalidateGroup(COUNT_GROUP_NAME);
rmCache.invalidateGroup(ALL);
// 刷新其父目录的所有文章的列表缓存(不包含父目录本身),此法已经弃用,因为这样程序的复杂度会增加,在更新时要多考虑其父结点
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + CHILDREN_OF_PARENT +
parent_code);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void refreshChangeDirCode(String dirCodeFrom, String dirCodeTo) {
try {
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + dirCodeFrom);
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + dirCodeTo);
rmCache.invalidateGroup(COUNT_GROUP_NAME);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void refreshDel(int id, String dir_code, String parent_code) {
// 更新缓存
removeFromCache(id);
// 清组DOCBLOCKCACHEPRIX缓存
try {
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + dir_code);
rmCache.invalidateGroup(COUNT_GROUP_NAME);
rmCache.invalidateGroup(ALL);
// 刷新其父目录的所有文章的列表缓存(不包含父目录本身)
rmCache.invalidateGroup(DOCBLOCKCACHEPRIX + CHILDREN_OF_PARENT +
parent_code);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void removeFromCache(int id) {
try {
rmCache.remove(cachePrix + id);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
protected long[] getDocBlock(String query, String groupKey, int startIndex) {
// First, discover what block number the results will be in.
int blockID = startIndex / DOC_BLOCK_SIZE;
int blockStart = blockID * DOC_BLOCK_SIZE;
// Now, check cache to see if the block is already cached. The key is
// simply the query plus the blockID.
String key = query + blockID;
long[] longArray = null;
try {
// logger.info("getDocBlock:" +DOCBLOCKCACHEPRIX + groupKey);
longArray = (long[]) rmCache.getFromGroup(key,
DOCBLOCKCACHEPRIX + groupKey);
} catch (Exception e) {
logger.error(e.getMessage());
}
//If already in cache, return the block.
if (longArray != null) {
/**
* The actual block may be smaller than THREAD_BLOCK_SIZE. If that's
* the case, it means two things:
* 1) We're at the end boundary of all the results.
* 2) If the start index is greater than the length of the current
* block, than there aren't really any results to return.
*/
long[] docs = longArray;
//当startIndex过大时
if (startIndex >= blockStart + docs.length) {
// Return an empty array
return EMPTY_BLOCK;
} else {
return docs;
}
}
// Otherwise, we have to load up the block from the database.
else {
Vector DocBlock = new Vector();
Conn conn = new Conn(connname);
ResultSet rs = null;
try {
// Set the maxium number of rows to end at the end of this block.
conn.setMaxRows(DOC_BLOCK_SIZE * (blockID + 1));
rs = conn.executeQuery(query);
//logger.info("query=" + query);
// Grab THREAD_BLOCK_ROWS rows at a time.
conn.setFetchSize(DOC_BLOCK_SIZE);
// Many JDBC drivers don't implement scrollable cursors the real
// way, but instead load all results into memory. Looping through
// the results ourselves is more efficient.
for (int i = 0; i < blockStart; i++) {
rs.next();
}
// Keep reading results until the result set is exaughsted or
// we come to the end of the block.
int count = 0;
while (rs.next() && count < DOC_BLOCK_SIZE) {
DocBlock.addElement(new Long(rs.getLong(1)));
count++;
}
} catch (SQLException sqle) {
logger.error("getDocBlock: " + sqle.getMessage());
// sqle.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {}
rs = null;
}
if (conn != null) {
conn.close();
conn = null;
}
}
int len = DocBlock.size();
long[] docs = new long[len];
for (int i = 0; i < len; i++) {
docs[i] = ((Long) DocBlock.elementAt(i)).longValue();
}
// Add the thread block to cache
try {
rmCache.putInGroup(key, DOCBLOCKCACHEPRIX + groupKey, docs);
} catch (Exception e) {
logger.error("getDocBlock1:" + e.getMessage());
}
/**
* The actual block may be smaller than THREAD_BLOCK_SIZE. If that's
* the case, it means two things:
* 1) We're at the end boundary of all the results.
* 2) If the start index is greater than the length of the current
* block, than there aren't really any results to return.
*/
if (startIndex >= blockStart + docs.length) {
// Return an empty array
return EMPTY_BLOCK;
} else {
return docs;
}
}
}
/**
*
* @param sql String
* @return int -1 表示sql语句不合法
*/
public int getDocCount(String sql) {
//根据sql语句得出计算总数的sql查询语句
String query = SQLFilter.getCountSql(sql);
if (!SecurityUtil.isValidSql(query))
return -1;
Integer count = null;
try {
count = (Integer) rmCache.getFromGroup(query, COUNT_GROUP_NAME);
} catch (Exception e) {
logger.error(e.getMessage());
}
// If already in cache, return the count.
if (count != null) {
return count.intValue();
}
// Otherwise, we have to load the count from the db.
else {
int docCount = 0;
Conn conn = new Conn(connname);
ResultSet rs = null;
try {
rs = conn.executeQuery(query);
if (rs.next())
docCount = rs.getInt(1);
} catch (SQLException sqle) {
sqle.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if (conn != null) {
conn.close();
conn = null;
}
}
// Add the thread count to cache
try {
rmCache.putInGroup(query, COUNT_GROUP_NAME,
new Integer(docCount));
} catch (Exception e) {
logger.error(e.getMessage());
}
return docCount;
}
}
public Document getDocument(int id) {
Document doc = (Document) rmCache.get(cachePrix + id);
if (doc == null) {
doc = new Document(id);
if (doc.isLoaded()) {
try {
rmCache.put(cachePrix + id, doc);
} catch (Exception e) {
logger.error("getDocument:" + e.getMessage());
}
return doc;
}
else
return null;
} else {
doc.renew();
return doc;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -