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