在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文件: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
" http://ibatis-with-memcached.googlecode.com/files/sql-map-config-2.dtd"> #注意这里,不用官方的,这个dtd文件加了个新属性databaseUrl,区分不同数据库的缓存对象
<sqlmapconfig>
<properties resource="cache_config.properties">
</properties>
<settingscacheModelsEnabled="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; |
} |
} |