在项目中使用Memcached缓存数据虽然让性能提高了很多,但是在管理缓存的过程中确有很多的问题。
这在先晒下配置
memcached.properties:
memcached.host=127.0.0.1
memcached.port=11211
memcached.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean name="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">
<!--
XMemcachedClientBuilder have two arguments.First is server list,and
second is weights array.
-->
<constructor-arg>
<bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>${memcached.host}</value>
</constructor-arg>
<constructor-arg>
<value>${memcached.port}</value>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<value>1</value>
</constructor-arg>
<property name="connectionPoolSize" value="2"></property>
<property name="commandFactory">
<bean class="net.rubyeye.xmemcached.command.TextCommandFactory"></bean>
</property>
<property name="sessionLocator">
<bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
</property>
<property name="transcoder">
<bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
</property>
</bean>
<!-- Use factory bean to build memcached client -->
<bean name="memcachedClient" factory-bean="memcachedClientBuilder"
factory-method="build" destroy-method="shutdown" />
</beans>
配置就不介绍了,自己也上网上找的。主要也是主机和端口这些东西。
这里主要讲一下自己对memcached中key的管理
都知道memcached就像map<string,T>一样。
如果让自己的key不重复,让memcached中的东西不常驻内存。
这里为memcached设置了一套操作接口
package com.zhr.memcached.operat.service;
import java.util.Set;
/**
* memcached 操作服务接口
*
* @author zhr
*
*/
public interface IMemcachedOperatService {
/**
* 获得此操作相关的key
*
* @param key
* @return
* @throws Exception
*/
public String getKey(String key) throws Exception;
/**
* 取出此操作相关的所有keySet
*
* @return
* @throws Exception
*/
public Set<String> getKeySet() throws Exception;
/**
* 清除此操作相关的所有cache
*
* @throws Exception
*/
public void clearMemcached() throws Exception;
/**
* 将对象放置到memcached内,默认过期时间到一天的结束
*
* @param <T>
* @param key
* @param t
* @throws Exception
*/
public <T> void put2Memcached(String key, T t) throws Exception;
/**
* 将对象放置到memcached内
*
* @param <T>
* @param key
* @param time
* 过期时间
* @param t
* @throws Exception
*/
public <T> void put2Memcached(String key, int time, T t) throws Exception;
/**
* 从memcached内取出对象
*
* @param <T>
* @param key
* @return
* @throws Exception
*/
public <T> T getFMemcached(String key) throws Exception;
/**
* 删除memcached内对象
*
* @param key
* key,默认是不完整的key(即通过上面的getKey()方法来获得key)
* @throws Exception
*/
public void deleteFMemcached(String key) throws Exception;
/**
* 删除memcached内对象
*
* @param key
* key
* @param isComplete
* 是否完整的key
* @throws Exception
*/
public void deleteFMemcached(String key, boolean isComplete)
throws Exception;
}
工具方法DateTimeUtil.getLastSecondFromNextDay();
public static final Long SECONDOFHOUR = 60L * 60;
private static final Long MSOFHOUR = SECONDOFHOUR * 1000;
public static int getLastSecondFromNextDay() {
Long timeMillis = System.currentTimeMillis();
int lastHours = 24 - Calendar.getInstance().get(Calendar.HOUR_OF_DAY) - 1;
Long last = (MSOFHOUR + 1000 - (timeMillis + MSOFHOUR) % MSOFHOUR) / 1000;
return (int) (lastHours * SECONDOFHOUR) + last.intValue();
}
实现:
package com.zhr.memcached.operat.service.impl;
import java.util.HashSet;
import java.util.Set;
import net.rubyeye.xmemcached.MemcachedClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zhr.memcached.operat.service.IMemcachedOperatService;
@Service
public class MemcachedOperatServiceImpl implements IMemcachedOperatService {
public String MEMCACHEDKEYPREFIX = "memcached-key-";
private String sign = "";
public void setSign(String sign) {
this.sign = sign;
}
public String getSign() {
return this.sign;
}
public String getMemcachedKeyPrefix(String key) {
return this.MEMCACHEDKEYPREFIX + getSign() + key;
}
public String getMemcachedKeySet() {
return this.MEMCACHEDKEYPREFIX + getSign() + "set";
}
@Autowired
private MemcachedClient memcachedClient;
@Override
public void clearMemcached() throws Exception {
Set<String> keySet = getKeySet();
for (String string : keySet) {
memcachedClient.delete(string);
}
}
@Override
public <T> T getFMemcached(String key) throws Exception {
// System.out.println("get from memcached -----> key : " + key + " , \tvalue : " + memcachedClient.get(key));
return memcachedClient.get(key);
}
@Override
public String getKey(String key) throws Exception {
String temp_key = getMemcachedKeyPrefix(key);
//每次返回key的时候都把相关的key保存起来
addKey2Set(temp_key);
return temp_key;
}
private void addKey2Set(String tempKey) throws Exception {
Set<String> keySet = getKeySet();
keySet.add(tempKey);
saveKeySet(keySet);
}
private void saveKeySet(Set<String> keySet) throws Exception {
put2Memcached(getMemcachedKeySet(), keySet);
}
@Override
public Set<String> getKeySet() throws Exception {
Set<String> keySet = getFMemcached(getMemcachedKeySet());
if (null == keySet) {
keySet = new HashSet<String>();
}
return keySet;
}
@Override
public <T> void put2Memcached(String key, T t) throws Exception {
int time = DateTimeUtil.getLastSecondFromNextDay();
put2Memcached(key, time, t);
}
@Override
public <T> void put2Memcached(String key, int time, T t) throws Exception {
if(null != t){
memcachedClient.set(key, time, t);
}
// System.out.println("put into memcached -----> key : " + key + " ,\tvalue : " + t);
}
@Override
public void deleteFMemcached(String key) throws Exception {
memcachedClient.delete(getKey(key));
}
@Override
public void deleteFMemcached(String key, boolean isComplete)
throws Exception {
memcachedClient.delete(isComplete ? key : getKey(key));
}
}
在这里为每一个memcached操作类配置一个标志sign属性代表这个操作。如:
<bean id="merchantNameMemcachedOperatServiceImpl" class="com.zhr.memcached.operat.service.impl.MemcachedOperatServiceImpl">
<property name="sign" value="merchant-name-"/>
</bean>
在service层配置
@Autowired
@Qualifier("merchantNameMemcachedOperatServiceImpl")
private IMemcachedOperatService memcachedNameOperatService;
@Override
public String getMerchantNameByCardId(Long id) throws Exception {
return memcachedNameOperatService.getFMemcached(memcachedNameOperatService.getKey(String.valueOf(id)));
}
@Override
public void setMerchantNameByCardId(Long id, String merchant)
throws Exception {
memcachedNameOperatService.put2Memcached(memcachedNameOperatService.getKey(String.valueOf(id)), merchant);
}
@Override
public void clearMerchantNameCache(){
memcachedNameOperatService.clearMemcached();
}
@Override
public void deleteMerchantNameById(Long id){
memcachedNameOperatService.deleteFMemcached(String.valueOf(id));
}
//在一些情况下,已经知道自己要清除的key的就用这方法
@Override
public void deleteMerchantNameByKey(String key){
memcachedNameOperatService.deleteFMemcached(key,true);
}
这样就把每一个memcached的操作都缓存起来了。