1) 概述:
听说公司有tc cache,可是没见着它在那里被应用了。而且他平时同事的编码中,每次要用到字典表的数据,总是QueryManager查询数据库。
昨天花了几个小时写了个简单的TCHelper,用户缓存TC表。
一般的情况下,我们字典表是不会发生变化的,有必要去cache我的字典表。
我的大体思路如下:
一:通过xml配置文件,配置所有的字典表查询sql.这样我们的sql和代码可以不在相干了。
这其中的sql有两种可能:
1:没有参数,对于这种sql,在初始化的时候就将得到数据,并且缓存起来。
2:带有参数的,这类sql我们没有办法再初始化的时间就执行,我们在xml中添加了一个简单的attribute
init="false" 二 :重新加载功能,这有两种可能:
1:字典表数据放生改变
2:配置的xml文件放生了变化。
对于字典表数据放生改变的情况,目前这个东西只是简单实现,并没有去检测数据库的数据,而是需要用户主动的方法
TCHelper.touch();
去修改配置文件最后更新时间。
我们只检测文件是否放生变化,如果放生变化才会去重新加载数据。2) 代码
/**//*
* Copyright (c) 2005 Print Information System Co.,Ltd. All Rights Reserved.
*/
package com.jxlt.adt.util;
import com.ptf.datastore.QueryManager;
import com.ptf.util.ClassLoaderUtil;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import java.io.File;
import java.sql.SQLException;
import java.util.*;
/** *//**
* 字典表cache
*
* @author martin xus
* @version 1.0 ,2005-10-26 11:29:33
*/
public class TCHelper {
///---------------------------------------------------------------
/// Instancd Data
///---------------------------------------------------------------
private static final Logger logger = Logger.getLogger(TCHelper.class);
private static Map sqlMap = new HashMap();
private static Map cache = new HashMap();
private static long lastModefied;
public static final String CONFIG_FILE = "tc_adt_sql.xml";
//---------------------------------------------------------------
// static block
//---------------------------------------------------------------
static {
logger.info("初始化TC Cache..");
init();
logger.info("初始化TC Cache完成");
}
//---------------------------------------------------------------
// public method
//---------------------------------------------------------------
/** *//**
* 根据指定的id返回缓存中的字典表数据
* 首先检测是否需要重新加载,若需要,则先加载
*
* @param key 配置在xml中的id
* @return key对应的字典表数据,
* 若没有对应的key,则返回emptyList
*/
public static List get(String key) {
logger.info("get tc value with key:" + key);
if (StringUtils.isBlank(key))
return null;
if (reload()) {
logger.info("reloading");
init();
logger.info("reloaded");
}
String _key = key.toLowerCase();
if (cache.containsKey(_key))
return getValue(key);
else
return emptyList();
}
/** *//**
* 这只针对于在初始化(init)没有初始化的字典表
*
* @param key xml配置文件中对应的id
* @param params sql参数
* @return key对应的字典表数据,
* 若没有对应的key,则返回emptyList
*/
public static List get(String key, List params) {
logger.info("PageHelper.getTCValue: key=" + key + " params=" + params);
if (StringUtils.isBlank(key))
return emptyList();
if (null == params)
throw new UnsupportedOperationException("不支持params为空的查询!");
String _key = key.toLowerCase();
if (sqlMap.containsKey(_key)) {
TCModel model = (TCModel) sqlMap.get(_key);
//logger.info("model:" + model);
try {
//todo:是否cache该变量
// cache.put(_key, _list);
return QueryManager.excuteSql(model.getSql(), params);
} catch (SQLException e) {
return emptyList();
}
} else {
logger.debug("invalid key!");
}
return emptyList();
}
/** *//**
* 修改文件的最后修改时间
* 这样当用户在查询字典表数据的时候,会重新init加载字典表数据
* 只有在字典表数据发生修改的时候才需要调用该方法。
*/
public static void touch() {
File file = getFile();
file.setLastModified(System.currentTimeMillis());
}
/** *//**
* 清除所有的cache,包括 cache 和 sqlMap
*/
public static void clearAll() {
cache.clear();
sqlMap.clear();
}
/** *//**
* 清除指定key
对应的字典表数据
*
* @param key 配置在xml文件中的id名称
*/
public static void clear(String key) {
if (StringUtils.isBlank(key))
return;
String _key = key.toLowerCase();
if (cache.containsKey(_key))
cache.remove(_key);
}
//---------------------------------------------------------------
// private method
//---------------------------------------------------------------
/** *//**
* 读取xml文件,初始化tc cache
*/
private static void init() {
logger.info("TCHelper.init() begin");
logger.info("Reading config from " + CONFIG_FILE);
File file = getFile();
lastModefied = file.lastModified();
logger.debug("file loaded.");
Element element = getRootElement(file);
Iterator iterator = element.getChildren().iterator();
while (iterator.hasNext()) {
TCModel model = new TCModel();
Element e = (Element) iterator.next();
String id = e.getAttributeValue("id");
if (StringUtils.isBlank(id))
continue;
String key = id.toLowerCase();
//
model.setId(key);
model.setAmount(e.getAttributeValue("amount") == null ? 2 : Integer.parseInt(e.getAttributeValue("amount")));
model.setInit(e.getAttributeValue("init") == null || Boolean.getBoolean(e.getAttributeValue("init")));
model.setSql(((Element) e.getChildren().get(0)) .getText());
if (model.isInit()) {
cache.put(key, initTCValues(model));
}
sqlMap.put(key, model);
}
}
/** *//**
* @param file
* @return Element
*/
private static Element getRootElement(File file) {
try {
SAXBuilder saxbuilder = new SAXBuilder();
Document document = saxbuilder.build(file);
lastModefied = file.lastModified();
return document.getRootElement();
} catch (JDOMException e) {
throw new RuntimeException("JDOMException:" + e.getMessage());
}
}
/** *//**
* @return File
*/
private static File getFile() {
File file = new File(ClassLoaderUtil.getResource(CONFIG_FILE, TCHelper.class).getFile());
if (!file.exists()) {
file = new File(TCHelper.class.getResource(CONFIG_FILE).getFile());
if (!file.exists())
throw new RuntimeException(CONFIG_FILE + " file not exists");
}
return file;
}
/** *//**
* @param model
* @return List
*/
private static List initTCValues(TCModel model) {
try {
//logger.info("model:" + model);
return QueryManager.excuteSql(model.getSql());
} catch (SQLException e) {
logger.error("SQLException:" + e.getMessage());
return null;
}
}
/** *//**
* @return boolean
*/
private static boolean reload() {
File file = getFile();
return lastModefied != file.lastModified();
}
/** *//**
* @return List
*/
private static List emptyList() {
return new ArrayList();
}
/** *//**
* @param key
* @return List
*/
private static List getValue(String key) {
return (List) cache.get(key);
}
/** *//**
* 字典表配置文件对应的Model
*/
protected static class TCModel {
private String id;
private int amount;
private boolean init;
private String sql;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public boolean isInit() {
return init;
}
public void setInit(boolean init) {
this.init = init;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
} 3)xml
我们的xml配置如下:
<?xml version="1.0" encoding="GB2312"?>
<sqlquery>
<query id="tc_reg_workmode">
<sql><![CDATA[
select t.workmodecode, t.workmodename
from TC_Reg_WorkMode t
where t.choiceflag = '1'
]]>sql>
query>
<query id="tc_pub_taxorgdept" init="false">
<sql><![CDATA[
select t.orgdeptcode,t.orgdeptname from tc_pub_taxorgdept t where t.auditflag='1' and t.orgdeptcode like ?
]]>sql>
query>
sqlquery>
end