XMemcached就是Memcached的java客户端之一,目前项目里用到了。据说它比起其他的java客户端从性能上要好一点,实现方式是NIO的。先看怎么实例化出来一个Memcached客户端吧:

    public static MilletMemcacheClient getIstance(String configPath) throws IOException {
try {
if (instance == null) {
synchronized (MilletMemcacheClient.class) {
if (instance == null) {
if (null == memEntity) {
logger.info("Load path:[ {} ] on etcd!",configPath);
ClientConfig config = ServiceDiscovery.getSingleton().read(configPath);
memEntity = new MilletMemcacheClientBuilder(AddrUtil.getAddressMap(StringUtils.trim(config.getIps())));
memEntity.setConnectionPoolSize(config.getLinksNum());
memEntity.setSessionLocator(new KetamaMemcachedSessionLocator());
}
MemcachedClient client = memEntity.build();
if (null != client) {
client.setMergeFactor(MERGE_FACTOR);
client.setConnectTimeout(CONNECT_TIMEOUT);
}
instance = new MilletMemcacheClient(client);
}
}
}
} catch (Exception e) {
logger.error("Init memcache client failed!", e);
throw e;
}
return instance;
}

  这里的memEntity继承了net.rubyeye.xmemcached.XMemcachedClientBuilder,而它的build方式具体实现是这样的:

    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClientBuilder#build()
*/
public MemcachedClient build() throws IOException {
XMemcachedClient memcachedClient;
// kestrel protocol use random session locator.
if (this.commandFactory.getProtocol() == Protocol.Kestrel) {
if (!(this.sessionLocator instanceof RandomMemcachedSessionLocaltor)) {
log.warn("Recommend to use `net.rubyeye.xmemcached.impl.RandomMemcachedSessionLocaltor` as session locator for kestrel protocol.");
}
}
if (this.weights == null) {
memcachedClient = new XMemcachedClient(this.sessionLocator,
this.bufferAllocator, this.configuration,
this.socketOptions, this.commandFactory, this.transcoder,
this.addressMap, this.stateListeners, this.authInfoMap,
this.connectionPoolSize, this.connectTimeout, this.name,
this.failureMode); } else {
if (this.addressMap == null) {
throw new IllegalArgumentException("Null Address map");
}
if (this.addressMap.size() > this.weights.length) {
throw new IllegalArgumentException(
"Weights Array's length is less than server's number");
}
memcachedClient = new XMemcachedClient(this.sessionLocator,
this.bufferAllocator, this.configuration,
this.socketOptions, this.commandFactory, this.transcoder,
this.addressMap, this.weights, this.stateListeners,
this.authInfoMap, this.connectionPoolSize,
this.connectTimeout, this.name, this.failureMode);
}
this.configureClient(memcachedClient);
return memcachedClient;
}

  我们可以看到这里需要配置一些参数,memcached的客户端就是根据这些参数来进行实例化的。当然大部分参数实际上都有默认值。这里最主要的是拿到memcached的地址和连接数。

  接着看具体操作,在这之前先看个序列化接口。我们存入和取出memcached的对象都是二进制的,那么必然要进行序列化,XMemcached给了我们接口

/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
// Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
package net.rubyeye.xmemcached.transcoders; /**
* Transcoder is an interface for classes that convert between byte arrays and
* objects for storage in the cache.
*/
public interface Transcoder<T> { /**
* Encode the given object for storage.
*
* @param o
* the object
* @return the CachedData representing what should be sent
*/
CachedData encode(T o); /**
* Decode the cached object into the object it represents.
*
* @param d
* the data
* @return the return value
*/
T decode(CachedData d); /**
* Set whether store primitive type as string.
*
* @param primitiveAsString
*/
public void setPrimitiveAsString(boolean primitiveAsString); /**
* Set whether pack zeros
*
* @param primitiveAsString
*/
public void setPackZeros(boolean packZeros);
/**
* Set compression threshold in bytes
* @param to
*/
public void setCompressionThreshold(int to); /**
* Returns if client stores primitive type as string.
* @return
*/
public boolean isPrimitiveAsString(); /**
* Returns if transcoder packs zero.
* @return
*/
public boolean isPackZeros(); /**
* Set compress mode,default is ZIP
* @see CompressionMode
* @param compressMode
*/
public void setCompressionMode(CompressionMode compressMode);
}

  既然给了接口,就是允许我们自己扩展的,当然如果不扩展,那么也可以用XMemcached自己的默认实现。下面看下存和取怎么实现

    public <T> boolean add(String key, int exp, T value, Transcoder<T> transcoder, long timeout)
throws MemcachedException
{
try
{
return mc.add(key, exp, value, transcoder, timeout);
}
catch (TimeoutException e)
{
onTimeoutException(OPERATE_ADD, key, e);
}
catch (InterruptedException e)
{
onInterruptedException(OPERATE_ADD, key, e);
} return false;
}

  这里的mc是一个接口,统一封装的XMemcached的操作,实际调用的是MemcachedClient的add方法

    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClient#add(java.lang.String, int, T,
* net.rubyeye.xmemcached.transcoders.Transcoder, long)
*/
public final <T> boolean add(String key, final int exp, final T value,
final Transcoder<T> transcoder, final long timeout)
throws TimeoutException, InterruptedException, MemcachedException {
key = this.preProcessKey(key);
return this.add0(key, exp, value, transcoder, timeout);
}
    private <T> boolean add0(String key, int exp, T value,
Transcoder<T> transcoder, long timeout)
throws InterruptedException, TimeoutException, MemcachedException {
byte[] keyBytes = this.checkStoreArguments(key, exp, value);
return this.sendStoreCommand(this.commandFactory.createAddCommand(key,
keyBytes, exp, value, false, transcoder), timeout);
}
    private final <T> boolean sendStoreCommand(Command command, long timeout)
throws InterruptedException, TimeoutException, MemcachedException { final Session session = this.sendCommand(command);
if (!command.isNoreply()) {
this.latchWait(command, timeout, session);
command.getIoBuffer().free();
this.checkException(command);
if (command.getResult() == null) {
throw new MemcachedException(
"Operation fail,may be caused by networking or timeout");
}
} else {
return false;
}
return (Boolean) command.getResult();
}
    private final <T> byte[] checkStoreArguments(final String key,
final int exp, final T value) {
byte[] keyBytes = ByteUtils.getBytes(key);
ByteUtils.checkKey(keyBytes);
if (value == null) {
throw new IllegalArgumentException("value could not be null");
}
if (exp < 0) {
throw new IllegalArgumentException(
"Expire time must be greater than or equal to 0");
}
return keyBytes;
}

  我们看到序列化方式作为参数transcoder被带进去了,针对key有checkKey校验,针对并发有latchWait限制。存的话返回一个布尔值,取直接返回对象

    public <T> T get(String key, long timeout, Transcoder<T> transcoder) throws MemcachedException
{
try
{
try
{
readController.beginTransaction();
}
catch (InterruptedException e)
{
onInterruptedException(OPERATE_GET, key, e);
} try
{
return mc.get(key, timeout, transcoder);
}
catch (TimeoutException e)
{
onTimeoutException(OPERATE_GET, key, e);
}
catch (InterruptedException e)
{
onInterruptedException(OPERATE_GET, key, e);
}
}
finally
{
readController.finishTransaction();
}
return null;
}
    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClient#get(java.lang.String, long,
* net.rubyeye.xmemcached.transcoders.Transcoder)
*/
@SuppressWarnings("unchecked")
public final <T> T get(final String key, final long timeout,
final Transcoder<T> transcoder) throws TimeoutException,
InterruptedException, MemcachedException {
return (T) this.get0(key, timeout, CommandType.GET_ONE, transcoder);
}
    private <T> Object get0(String key, final long timeout,
final CommandType cmdType, final Transcoder<T> transcoder)
throws TimeoutException, InterruptedException, MemcachedException {
key = this.preProcessKey(key);
byte[] keyBytes = ByteUtils.getBytes(key);
ByteUtils.checkKey(keyBytes);
return this.fetch0(key, keyBytes, cmdType, timeout, transcoder);
}
    @SuppressWarnings("unchecked")
private final <T> Object fetch0(final String key, final byte[] keyBytes,
final CommandType cmdType, final long timeout,
Transcoder<T> transcoder) throws InterruptedException,
TimeoutException, MemcachedException, MemcachedException {
final Command command = this.commandFactory.createGetCommand(key,
keyBytes, cmdType, this.transcoder);
this.latchWait(command, timeout, this.sendCommand(command));
command.getIoBuffer().free(); // free buffer
this.checkException(command);
CachedData data = (CachedData) command.getResult();
if (data == null) {
return null;
}
if (transcoder == null) {
transcoder = this.transcoder;
}
if (cmdType == CommandType.GETS_ONE) {
return new GetsResponse<T>(data.getCas(), transcoder.decode(data));
} else {
return transcoder.decode(data);
}
}

  我们看到执行memcached命令取到数据后执行了反序列化,把二进制变成了对象。而且这里在读取之前还加了事务控制,XMemcached是没有事务支持的,所以必须自己实现。同存操作,我们看到取操作也有针对key有checkKey校验,针对并发有latchWait限制。最后看下CAS的实现:

    public boolean cas(String key, int exp, Object value, long cas) throws MemcachedException
{
try
{
return mc.cas(key, exp, value, cas);
}
catch (TimeoutException e)
{
onTimeoutException(OPERATE_CAS, key, e);
}
catch (InterruptedException e)
{
onInterruptedException(OPERATE_CAS, key, e);
} return false;
}
    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int,
* java.lang.Object, long)
*/
public final boolean cas(final String key, final int exp,
final Object value, final long cas) throws TimeoutException,
InterruptedException, MemcachedException {
return this.cas(key, exp, value, this.opTimeout, cas);
}
    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int,
* java.lang.Object, long, long)
*/
@SuppressWarnings("unchecked")
public final boolean cas(final String key, final int exp,
final Object value, final long timeout, final long cas)
throws TimeoutException, InterruptedException, MemcachedException {
return this.cas(key, exp, value, this.transcoder, timeout, cas);
}
    /*
* (non-Javadoc)
*
* @see net.rubyeye.xmemcached.MemcachedClient#cas(java.lang.String, int, T,
* net.rubyeye.xmemcached.transcoders.Transcoder, long, long)
*/
public final <T> boolean cas(String key, final int exp, final T value,
final Transcoder<T> transcoder, final long timeout, final long cas)
throws TimeoutException, InterruptedException, MemcachedException {
key = this.preProcessKey(key);
byte[] keyBytes = this.checkStoreArguments(key, 0, value);
return this.sendStoreCommand(this.commandFactory.createCASCommand(key,
keyBytes, exp, value, cas, false, transcoder), timeout);
}
    private final <T> boolean sendStoreCommand(Command command, long timeout)
throws InterruptedException, TimeoutException, MemcachedException { final Session session = this.sendCommand(command);
if (!command.isNoreply()) {
this.latchWait(command, timeout, session);
command.getIoBuffer().free();
this.checkException(command);
if (command.getResult() == null) {
throw new MemcachedException(
"Operation fail,may be caused by networking or timeout");
}
} else {
return false;
}
return (Boolean) command.getResult();
}

  客户端的CAS并无特别之处,就跟执行ADD命令一样返回执行是否成功,只是多传了一个cas参数用于版本号的控制。跟存取操作一样,针对key有checkKey校验,针对并发有latchWait限制。

    public static final void checkKey(final byte[] keyBytes) {

        if (keyBytes.length > ByteUtils.maxKeyLength) {
throw new IllegalArgumentException("Key is too long (maxlen = "
+ ByteUtils.maxKeyLength + ")");
}
// Validate the key
if (memcachedProtocol == Protocol.Text || testing) {
for (byte b : keyBytes) {
if (b == ' ' || b == '\n' || b == '\r' || b == 0) {
try {
throw new IllegalArgumentException(
"Key contains invalid characters: "
+ new String(keyBytes, "utf-8")); } catch (UnsupportedEncodingException e) {
}
} }
}
}
private static int maxKeyLength = ;

  缓存KEY的字节数控制不能超过250。并发用闭锁控制,闭锁的创建和释放分别在Command对象的创建和Session对象的销毁,而锁住的动作则在执行命令之前:

  TextCommandFactory类:创建命令和闭锁,允许通过闭锁的线程数为1

    /*
* (non-Javadoc)
*
* @see
* net.rubyeye.xmemcached.CommandFactory#createGetCommand(java.lang.String,
* byte[], net.rubyeye.xmemcached.command.CommandType)
*/
@SuppressWarnings("unchecked")
public final Command createGetCommand(final String key,
final byte[] keyBytes, final CommandType cmdType,
Transcoder transcoder) {
return new TextGetOneCommand(key, keyBytes, cmdType,
new CountDownLatch(1));
}

  XMemcachedClient类:锁住,除非缓存命令操作结束,否则不允许其他线程进入;超时则取消命令

    protected void latchWait(final Command cmd, final long timeout,
final Session session) throws InterruptedException,
TimeoutException {
if (cmd.getLatch().await(timeout, TimeUnit.MILLISECONDS)) {
AtomicInteger counter = this.getContinuousTimeoutCounter(session);
// reset counter.
if (counter.get() > 0) {
counter.set(0);
}
} else {
cmd.cancel();
AtomicInteger counter = this.getContinuousTimeoutCounter(session);
if (counter.incrementAndGet() > this.timeoutExceptionThreshold) {
log.warn(session
+ " exceeded continuous timeout threshold,we will close it.");
try {
// reset counter.
counter.set(0);
session.close();
} catch (Exception e) {
// ignore it.
}
}
throw new TimeoutException(
"Timed out("
+ timeout
+ " milliseconds) waiting for operation while connected to "
+ session);
}
} private AtomicInteger getContinuousTimeoutCounter(final Session session) {
AtomicInteger counter = (AtomicInteger) session
.getAttribute(CONTINUOUS_TIMEOUT_COUNTER);
if (counter == null) {
counter = new AtomicInteger(0);
AtomicInteger oldCounter = (AtomicInteger) session
.setAttributeIfAbsent(CONTINUOUS_TIMEOUT_COUNTER, counter);
if (oldCounter != null) {
counter = oldCounter;
}
}
return counter;
}

  MemcachedHandler类:命令完成,销毁session

    public void destroy() {
Command command = this.currentCommand.get();
if (command != null) {
command.setException(new MemcachedException(
"Session has been closed"));
CountDownLatch latch = command.getLatch();
if (latch != null) {
latch.countDown();
}
}
while ((command = this.commandAlreadySent.poll()) != null) {
command.setException(new MemcachedException(
"Session has been closed"));
CountDownLatch latch = command.getLatch();
if (latch != null) {
latch.countDown();
}
} }

  最后再看一个实例化memcache缓存客户端、操作缓存的例子:

package com.wulinfeng.memcache.view.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import com.fasterxml.jackson.core.JsonProcessingException;
import com.wulinfeng.memcache.view.bean.MemcacheViewBean;
import com.wulinfeng.memcache.view.util.HttpClientUtil;
import com.wulinfeng.memcache.view.util.PropertiesConfigUtil; /**
* memcache展示业务逻辑类
*
* @author wulinfeng
* @version C10 2017年11月21日
* @since SDP V300R003C10
*/
@Service
public class MemcacheViewService
{
private static Logger LOGGER = LogManager.getLogger(MemcacheViewService.class); private static List<MemcacheViewBean> memcacheCategoryList = new ArrayList<>(); private static Map<String, String> cacheDataMap = new HashMap<>(); private static final String CONFIG_FILE = "/memcache_config.xml"; private static final String TEST_URL = PropertiesConfigUtil.getProperty("test_url"); /**
* 启动加载缓存信息
*
* @author wulinfeng
*/
public static void init()
{
// 1、加载缓存分类列表
initializeCacheList(); // 2、加载缓存客户端实例
getMemcacheClient();
} /**
* 获取缓存分类列表
*
* @author wulinfeng
* @return
*/
public MemcacheViewBean[] getMemcacheCategory()
{
return (MemcacheViewBean[])(memcacheCategoryList.toArray(new MemcacheViewBean[memcacheCategoryList.size()]));
} /**
* 针对缓存的查、删、改
*
* @author wulinfeng
* @param operationType
* @param key2
* @return
* @throws JsonProcessingException
*/
public String doMemcached(String operationType, String cacheName, String key)
{
String result = null;
XMemcachedClient client = XMemcachedClient.getMemcachedClient();
switch (operationType)
{
case "1":// 根据key查缓存
Object obj = client.getObject(key);
result = (String)obj;
break;
case "2":// 根据key删缓存
if (client.deleteObject(key))
{
result = "{\"msg\":\"delete sucess\"}";
}
break;
case "3":// 根据缓存名找到查数据接口名,调用接口获取数据
String dataLoaderName = cacheDataMap.get(cacheName);
if (StringUtils.isNotEmpty(dataLoaderName))
{
result = HttpClientUtil.sendRequestByGetAsync(TEST_URL + dataLoaderName);
}
if (result != null)
{
client.addObject(key, result, 0);
}
break;
default:
;
} return result;
} /**
* 加载缓存客户端
*
* @author wulinfeng
* @return
*/
private static void getMemcacheClient()
{
String mcListStr = PropertiesConfigUtil.getProperty("memcache.server", ""); if (StringUtils.isEmpty(mcListStr))
{
LOGGER.error("Get MemcacheClient Error ! mcListStr is null !");
return;
}
String[] mcList = mcListStr.split(",");
try
{
XMemcachedClient.getInstance(PropertiesConfigUtil.getInt("memcache.linksNum", 1), mcList);
}
catch (IOException e)
{
LOGGER.error("Get MemcacheClient Error ! e:" + e);
e.printStackTrace();
}
} /**
* 加载缓存分类列表
*
* @author wulinfeng
*/
private static void initializeCacheList()
{
memcacheCategoryList.clear();
cacheDataMap.clear();
try
{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
builder = builderFactory.newDocumentBuilder();
String basePath = ResourceUtils.getFile("classpath:").getPath();
String configPath = basePath + CONFIG_FILE;
Document doc = builder.parse(configPath);
NodeList itemNodes = doc.getElementsByTagName("item"); for (int itemIndex = 0; itemIndex < itemNodes.getLength(); itemIndex++)
{
Element itemElem = (Element)itemNodes.item(itemIndex);
NodeList childList = itemElem.getChildNodes();
String cacheName = ""; MemcacheViewBean memcacheViewBean = new MemcacheViewBean();
for (int i = 0; i < childList.getLength(); i++)
{
Node childNode = childList.item(i); if (childNode.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element)childNode;
String tagName = element.getTagName();
String textContent = element.getTextContent().trim(); switch (tagName)
{
case "cacheName":
cacheName = textContent;
memcacheViewBean.setCacheName(textContent);
break;
case "keyProfix":
memcacheViewBean.setKeyProfix(textContent);
break;
case "supportRefresh":
memcacheViewBean.setSupportRefresh(textContent.equals("1"));
break;
case "dataLoaderName":
cacheDataMap.put(cacheName, textContent);
break;
default: }
}
} memcacheCategoryList.add(memcacheViewBean);
}
}
catch (Throwable e)
{
LOGGER.error("MemcacheViewService.init failed, e: ", e);
}
}
}
package com.wulinfeng.memcache.view.service;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import net.rubyeye.xmemcached.GetsResponse;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import net.rubyeye.xmemcached.utils.AddrUtil; /**
* memcache缓存客户端
*
* @author wulinfeng
* @version C10 2017年11月22日
* @since SDP V300R003C10
*/
public class XMemcachedClient
{ private final static Logger LOGGER = LoggerFactory.getLogger(XMemcachedClient.class); /**
* 批量请求,每批次请求数量
*/
private final static int MERGE_FACTOR = 20; /**
* 链接超时时间
*/
private final static int CONNECT_TIMEOUT = 500; /**
* 超时时间的配置 单位:毫秒
*/
protected static final long REQUEST_TIME_OUT = 1000; /**
* 步长
*/
private final long STEP = 1L; /**
* 默认值
*/
private final long DEFAULTVALUE = 0; private static XMemcachedClientBuilder memEntity; private static volatile XMemcachedClient instance; private MemcachedClient mc; private XMemcachedClient(MemcachedClient memcachedClient)
throws IOException
{
this.mc = memcachedClient;
} /**
* 实例化客户端,单例模式
*
* @author wulinfeng
* @param linksNum
* @param memcacheIp
* @return
* @throws IOException
*/
public static XMemcachedClient getInstance(int linksNum, String... memcacheIp)
throws IOException
{
try
{
if (instance == null)
{
synchronized (XMemcachedClient.class)
{
if (instance == null)
{
if (0 != memcacheIp.length)
{
memEntity = new XMemcachedClientBuilder(
AddrUtil.getAddressMap(StringUtils.trim(array2string(memcacheIp))));
if (0 != linksNum)
{
memEntity.setConnectionPoolSize(linksNum);
}
} // 节点挂掉返回失败,不会自动路由到其他节点
memEntity.setFailureMode(true); // 选择一致性哈希算法
memEntity.setSessionLocator(new KetamaMemcachedSessionLocator());
MemcachedClient client = memEntity.build();
if (null != client)
{
client.setMergeFactor(MERGE_FACTOR);
client.setConnectTimeout(CONNECT_TIMEOUT);
}
client.setEnableHeartBeat(true);
client.setEnableHealSession(true); // 网络关闭,失败,重试间隔时间间隔,10毫秒
client.setHealSessionInterval(10);
instance = new XMemcachedClient(client);
}
}
}
}
catch (Exception e)
{
LOGGER.error("Init memcache client failed!", e);
throw e;
}
return instance;
} /**
* 获取缓存客户端实例给外部
*
* @author wulinfeng
* @return
*/
public static XMemcachedClient getMemcachedClient()
{
return instance;
} /**
* 根据key值从IMemcachedClient获取缓存对象
*
* @param key 缓存的Key
* @return 缓存对象
*/
public Object getObject(String key)
{
try
{
Object result = mc.get(key, REQUEST_TIME_OUT);
return result;
}
catch (Exception e)
{
LOGGER.error("get memcached faield : ", key, e);
}
return null;
} /**
* 根据key值从IMemcachedClient获取缓存对象
*
* @param key 缓存的Key
* @param obj Object
* @param time int
* @return 缓存对象
*/
public boolean addObject(String key, Object obj, int time)
{
// 是否添加成功
boolean rst = false;
int expire = 0;
if (0 != time)
{
expire = (int)(System.currentTimeMillis() / 1000) + time;
}
try
{
rst = mc.add(key, expire, obj, REQUEST_TIME_OUT);
}
catch (Exception e)
{
LOGGER.error("add memcached faield : ", key, e);
}
return rst;
} /**
* 根据key值从IMemcachedClient获取缓存对象
*
* @param key 缓存的Key
* @return 缓存对象
*/
public Object getsObject(String key)
{
try
{
GetsResponse result = mc.gets(key, REQUEST_TIME_OUT);
return result;
}
catch (Exception e)
{
LOGGER.error("gets memcached faield : ", key, e);
}
return null;
} /**
* 根据key值从IMemcachedClient删除缓存对象
*
* @param key 缓存的Key
* @return 是否成功删除
*/
public boolean deleteObject(String key)
{
try
{
boolean result = mc.delete(key, REQUEST_TIME_OUT);
return result;
}
catch (Exception e)
{
LOGGER.error("delete memcached faield : ", key, e);
}
return false;
} /**
* 根据key值和更新对象,在Memcached中更新缓存对象
*
* @param key 缓存的Key
* @param data 缓存对象
* @param time int
* @return 是否成功更新
*/
public boolean updateObject(String key, Object data, int time)
{
boolean rst = false;
try
{
GetsResponse getsResponse = mc.gets(key);
if (null != getsResponse)
{
int expire = 0;
if (0 != time)
{
expire = (int)(System.currentTimeMillis() / 1000) + time;
}
rst = mc.cas(key, expire, data, REQUEST_TIME_OUT, getsResponse.getCas());
}
}
catch (Exception e)
{
LOGGER.error("update memcached faield : ", key, e);
}
return rst;
} /**
* 根据key值和更新对象,在Memcached中更新缓存对象 与updateObject不同之处在于不需要乐观锁判断,避免并发更新同一个主键对象失败
*
* @param key 缓存的Key
* @param data 缓存对象
* @param time int
* @return 是否成功更新
*/
public boolean updateObject2(String key, Object data, int time)
{
int expire = 0;
boolean result = false;
if (0 != time)
{
expire = (int)(System.currentTimeMillis() / 1000) + time;
}
try
{
result = mc.set(key, expire, data, REQUEST_TIME_OUT);
}
catch (Exception e)
{
LOGGER.error("update memcached faield : ", key, e);
}
return result;
} /**
* 缓存累加器
*
* @author wulinfeng
* @param key 缓存key
* @param initValue 初始化的值
* @param invalidDurance 失效时间
* @return
*/
public long incr(String key, long initValue, int invalidDurance)
{
int expire = 0;
if (0 != invalidDurance)
{
expire = (int)(System.currentTimeMillis() / 1000) + invalidDurance;
}
try
{
long result = mc.incr(key, STEP, initValue, REQUEST_TIME_OUT, expire);
return result;
}
catch (Exception e)
{
LOGGER.error("incr memcached faield : ", key, e);
}
return 0;
} /**
* 递减计数器
*
* @author wulinfeng
* @param key 缓存key
* @param invalidDurance 失效时间
* @return
*/
public long decr(String key, int invalidDurance)
{
int expire = 0;
if (0 != invalidDurance)
{
expire = (int)(System.currentTimeMillis() / 1000) + invalidDurance;
}
try
{
long result = mc.decr(key, STEP, DEFAULTVALUE, REQUEST_TIME_OUT, expire);
return result;
}
catch (Exception e)
{
LOGGER.error("incr memcached faield : ", key, e);
}
return 0;
} /**
* @param szList
* @return
*/
private static String array2string(String[] szList)
{
StringBuilder sb = new StringBuilder();
for (String szTmp : szList)
{
sb.append(szTmp).append(",");
}
return sb.substring(0, sb.lastIndexOf(","));
}
}

  

  

XMemcached使用经历的更多相关文章

  1. H5拍照应用开发经历的那些坑儿

    一.项目简介 1.1.项目背景:这是一个在移动终端创新应用的项目,用户在浏览器端(微信/手Q)即可完成与金秀贤的合影,希望通过这样一种趣味体验,引发用户的分享与转发的热潮. 1.2.系统要求:ios6 ...

  2. 记2016腾讯 TST 校招面试经历,电面、笔试写代码、技术面、hr面,共5轮

    (出处:http://www.cnblogs.com/linguanh/) 前序: 距离  2016 腾讯 TST 校招面试结束已经5天了,3月27日至今,目前还在等待消息.从投简历到两轮电面,再到被 ...

  3. 阿里提前批校招内推offer经历

    经过一个半月的阿里内推面试,今天终于收到了阿里的offer邮件 .阿里的内推面试一共有四轮,本人是7月19号投的内推邮件,8月28号收到了offer的邮件.首先本人谈谈内推的看法.内推是公司招聘人才的 ...

  4. Ubuntu服务器被黑经历(ElastichSearch漏洞)

    起因 最近我们的一台Ubuntu阿里云服务器一直提示有肉鸡行为,提示了好几天,开始并没有关注,然后连续几天后发现应该是个大问题啊.很可能服务被侵入了!!! 寻找线索 一开始我是完全懵逼的状态的,Lin ...

  5. CVTE实习求职经历

    今天,听到有好多同学最近要去面试CVTE这家企业,于是呢,准备将自己的经历写上来,给大家一个参考,希望能够大家一次帮助. 一.整体感觉 首先呢,先讲一下我个人对这家企业的整体感觉吧. 1. 第一次 对 ...

  6. geotrellis使用(七)记录一次惨痛的bug调试经历以及求DEM坡度实践

    眼看就要端午节了,屌丝还在写代码,话说过节也不给轻松,折腾了一天终于解决了一个BUG,并完成了老板安排的求DEM坡度的任务,那么就分两段来表. 一.BUG调试 首先记录一天的BUG调试,简单copy了 ...

  7. 淘宝web前端开发岗面试经历及感悟

    今天下午四点接到淘宝UED的面试电话,很突然,很激动.现在怀着淡淡的忧伤为之文以志一下. 1.自我介绍一下. 我xx时候毕业,在xx公司任xx职务,主要负责xx balabala.(怕公司同事听到,接 ...

  8. [分享] 很多人手机掉了,却不知道怎么找回来。LZ亲身经历讲述手机找回过程,申请加精!

    文章开头:(LZ文笔不好,以下全部是文字描述,懒得配图.因为有人说手机掉了,他们问我是怎么找回来的.所以想写这篇帖子.只不过前段时间忙,没时间.凑端午节给大家一些经验) 还是先谢谢被偷经历吧!5月22 ...

  9. iftop与dstat-一次网站故障分析经历

    一次网站分析与解决的经历,最后结果虽然很简单但是过程比较曲折.记录一下: 今天访问网站首页十分缓慢,页面半天都加载不出来.于是上服务器看看情况,通过top看到load和cpu以及磁盘io都很低,只能祭 ...

随机推荐

  1. 使用nagios检测windows服务器

    1.安装nagios windows客户端 下载NSClient++的安装包,注意根据实际的32/64CPU来下载 下载地址 http://sourceforge.net/projects/nscpl ...

  2. Pandas面板(Panel)

    面板(Panel)是3D容器的数据.面板数据一词来源于计量经济学,部分源于名称:Pandas - pan(el)-da(ta)-s. 3轴(axis)这个名称旨在给出描述涉及面板数据的操作的一些语义. ...

  3. NumPy数组属性

    NumPy - 数组属性 这一章中,我们会讨论 NumPy 的多种数组属性. ndarray.shape 这一数组属性返回一个包含数组维度的元组,它也可以用于调整数组大小. 示例 1 import n ...

  4. vue开发者工具DejaVue

    刚刚在逛github的时候发现了一个vue开发工具觉得很不错,分享给v友们! 地址:https://github.com/MiCottOn/DejaVue 话不多说,直接说操作流程!(前提是node版 ...

  5. poj3468线段树标记永久化

    #include<map> #include<set> #include<list> #include<cmath> #include<queue ...

  6. tomcat学习篇

    要求: 为Apache HTTP Server服务器添加JSP网页支持. 能够访问Tomcat容器的Web管理界面,以便管理各种JSP.Servelet应用. u 知识提示 在各种企业级网站应用系统中 ...

  7. python 超时异常处理

    异常处理具体见:[循序渐进学Python]9.异常处理 环境平台:Python2.7.9 + Win8.1 本篇记录一下自己写爬虫的遇到的问题,程序中批量获取图片地址,然后批量保存.由于没有设置网址打 ...

  8. ubuntu 安装python3.7 以及安装pip3 出现Command '('lsb_release', '-a')' returned non-zero exit status 1问题解决

    最近因为电脑重装,东西全没了,总计一下最近重装环境的过程. 如果没有安装包,请下载: wget http://www.python.org/ftp/python/3.7.0/Python-3.7.0. ...

  9. CentOS7 安装ifconfig

    As we all know, “ifconfig” command is used to configure a network interfaces in GNU/Linux systems. I ...

  10. [JS学习笔记]Event对象

    写在前面 学习和总结JS时会伴随性的生成一些dome,其中包含一些动态输出的结果和标注. 之前通过鸡贼的办法实现了在博客中执行JS,但很多时候需要一张干净的页面编写dome,所以尝试通过一些在线的JS ...