84086320 2011-07-14
在ibatis源码基础上修改,增加对memcached支持,通过配置IBatis的xml文件即可实现memcached细粒度话缓存,使用简单,缓存效果好。spring下首先初始化MemcachedManager对象,或者通过程序初始化也一样,不要用ibatis官方的jar包,否则会冲突
<bean class="com.ibatis.sqlmap.engine.cache.memcached.memcachedManager" lazy-init="false" init-method="init" destroy-method="closePool"> <property name="serverlist"> <value> 192.168.0.1:11111, 192.168.0.2:11111 </value> </property> <property name="initConn" value="5"> </property> <property name="minConn" value="5"> </property> <property name="maxConn" value="200"> </property> Unknown end tag for </bean>
然后配置sqlMapConfig.xml文件:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEsqlMapConfigPUBLIC"-//iBATIS.com//DTDSQLMapConfig2.0//EN"
"http://ibatis-with-memcached.googlecode.com/files/sql-map-config-2.dtd">#注意这里,不用官方的,这个dtd文件加了个新属性databaseUrl,区分不同数据库的缓存对象
<sqlmapconfig> <properties resource="cache_config.properties"> </properties> <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" maxRequests="256" maxSessions="256" maxTransactions="150" useStatementNamespaces="true" databaseUrl="数据库名或地址" #新增加的属性 /> ibatis的xml文件:Albums.xml #创建缓存model <cachemodel type="MEMCACHED" id="albumsCache"> <flushinterval hours="12"> </flushInterval > <flushonexecute statement="albums.save"> </flushOnExecute > <flushonexecute statement="albums.update"> </flushOnExecute > <flushonexecute statement="albums.delete"> </flushOnExecute > <property name="pk" value="id"> </property> #可以根据主键进行缓存,可以设置为空,不能不设 <property name="groupField" value="accId"> </property> #可以根据组(比如用户id)进行缓存,更加细粒度化,可以设置为空,不能不设 Unknown end tag for </cachemodel> #加入缓存 <select id="findall" parameterClass="albumsObj" resultClass="albumsObj" cacheModel="albumsCache"> Select ……from albums where accId=1 </select> <select id="load" parameterClass="albumsObj" resultClass="albumsObj" cacheModel="albumsCache"> Select ……from albums where id=1 </select> #删除对象,删除缓存 <delete id="delete" parameterClass="albumsObj"> delete from albums where id=1 and accId=1 #(加上accId可以删除分组缓存) </delete>
package com.ibatis.sqlmap.engine.cache.memcached; import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.Map; import org.apache.log4j.Logger; import com.danga.MemCached.MemCachedClient; import com.danga.MemCached.SockIOPool; public class MemcachedManager { private static Logger logger = Logger.getLogger(MemcachedManager.class); private static String memcachedDomain = "IBATIS_CACHED"; // memcached 域名 private String serverlist; private static MemCachedClient mcc = null; private SockIOPool pool = null; private int initConn = 5; private int minConn = 5; private int maxConn = 50; public void init() { if (mcc != null) return; logger.info("Initializing ibatis memcached start."); if (pool == null) { try { pool = SockIOPool.getInstance(memcachedDomain); pool.setServers(serverlist.split(",")); if (!pool.isInitialized()) { pool.setInitConn(initConn); pool.setMinConn(minConn); pool.setMaxConn(maxConn); pool.setMaintSleep(30); pool.setNagle(false); pool.setSocketTO(60 * 60); pool.setSocketConnectTO(0); pool.initialize(); } } catch (Exception ex) { logger.error(ex.getMessage()); } } if (mcc == null) { mcc = new MemCachedClient(memcachedDomain); mcc.setCompressEnable(false); mcc.setCompressThreshold(0); } logger.info("Initializing youxigu Memcached ok!"); } public void closePool() { pool.shutDown(); mcc = null; pool = null; logger.info("Ibatis memcached pool closed"); } public static boolean set(Object key, Serializable obj) { logger.debug("set key:" + getKey(key) + ", value:" + obj); try { return mcc.set(getKey(key), obj); } catch (Exception e) { logger.error("Pool set error!"); e.printStackTrace(); } return false; } public static boolean set(Object key, Serializable obj, long cacheTime) { try { return mcc.set(getKey(key), obj, new Date(cacheTime)); } catch (Exception e) { logger.error("Pool set error!"); e.printStackTrace(); } return false; } public static void replace(int key, Serializable value, long cacheTime) { try { mcc.replace(getKey(key), value, new Date(cacheTime)); } catch (Exception e) { logger.error(" pool set error!"); } } public static Object get(Object key) { Object result = null; String realkey = getKey(key); try { result = mcc.get(realkey); } catch (Exception e) { e.printStackTrace(); } logger.debug("get key:" + getKey(key) + ", value:" + result); return result; } public static void setCounter(Object key, long count) { try { mcc.storeCounter(getCountKey(key), count); } catch (Exception e) { logger.error("Pool setCounter error!"); } } public static void addCounter(Object key) { if(mcc.get(getCountKey(key))==null){ mcc.storeCounter(getCountKey(key), 0); } try { mcc.incr(getCountKey(key)); } catch (Exception e) { logger.error("Pool setCounter error!"); } } public static void decreaseCounter(Object key) { try { mcc.decr(getCountKey(key)); } catch (Exception e) { logger.error("Pool setCounter error!"); } } public static void addCounter(Object key, long addValue) { try { mcc.incr(getCountKey(key), addValue); } catch (Exception e) { logger.error(" pool setCounter error!"); } } public static long getCounter(Object key) { long result = 0; try { result = mcc.getCounter(getCountKey(key)); } catch (Exception e) { logger.error(e.getMessage()); } return result; } public static boolean delete(Object key) { try { return mcc.delete(getKey(key)); } catch (Exception e) { logger.error(e.getMessage()); } return false; } public static long deleteCounter(Object key) { try { return mcc.decr(getCountKey(key)); } catch (Exception e) { logger.error(" pool setCounter error!"); } return 0; } public static void flushAll() { mcc.flushAll(); } @SuppressWarnings("unchecked") public static long size(){ long size=0L; Map<String,Map<String,String>> status=mcc.statsItems(); Collection<Map<String,String>> values=status.values(); for (Map<String,String> state:values) { String num=state.get("items:1:number"); if(num==null) continue; size+=Long.parseLong(state.get("items:1:number")); } return size; } private static String getKey(Object key) { return memcachedDomain + "@" + key; } private static String getCountKey(Object key) { return memcachedDomain + "@" + key + "_count"; } public void setServerlist(String serverlist) { this.serverlist = serverlist; } public void setInitConn(int initConn) { this.initConn = initConn; } public void setMinConn(int minConn) { this.minConn = minConn; } public void setMaxConn(int maxConn) { this.maxConn = maxConn; } public void setMemcachedDomain(String memcachedKey) { MemcachedManager.memcachedDomain = memcachedKey; } }
如:对于sql语句order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id"。