介紹
memcached java client是官方推薦的最早的memcached java用戶端。最新版本:java_memcached-release_2.6.1。
官方下載下傳位址:https://github.com/gwhalin/memcached-java-client
采用阻塞式socket通訊,據說目前版本進行了很多優化,性能有所提高(隻看過1.5的源代碼,還沒來及看最新的)
提供key方式的連接配接池,預設連接配接池key為default。(老版本了)。2.6.1版本支援apache-commoms-pool作為連接配接池。
支援權重配置。
後期的版本提增加了cas支援和getmutl功能
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
import com.danga.memcached.memcachedclient;
import com.danga.memcached.sockiopool;
import com.schooner.memcached.memcacheditem;
public class memcachedforjavaexample {
// create a static client as most installs only need
// a single instance
protected static memcachedclient mcc = new memcachedclient();
// set up connection pool once at class load
static {
// server list and weights
string[] servers = { "localhost:11211", "localhost:11212", "localhost:11213" };
integer[] weights = { 3, 3, 2 };
// grab an instance of our connection pool
sockiopool pool = sockiopool.getinstance();
// set the servers and the weights
pool.setservers(servers);
pool.setweights(weights);
pool.sethashingalg(sockiopool.consistent_hash);
// set some basic pool settings
// 5 initial, 5 min, and 250 max conns
// and set the max idle time for a conn
// to 6 hours
pool.setinitconn(5);
pool.setminconn(5);
pool.setmaxconn(250);
pool.setmaxidle(1000 * 60 * 60 * 6);
// set the sleep for the maint thread
// it will wake up every x seconds and
// maintain the pool size
pool.setmaintsleep(30);
// set some tcp settings
// disable nagle
// set the read timeout to 3 secs
// and don't set a connect timeout
pool.setnagle(false);
pool.setsocketto(3000);
pool.setsocketconnectto(0);
// initialize the connection pool
pool.initialize();
}
public static void main(string[] args) {
system.out.println("set: " + mcc.set("key1", "value1"));
system.out.println("set: " + mcc.set("key2", "value2"));
system.out.println("set: " + mcc.set("key3", "value3"));
system.out.println("get: " + mcc.get("key1"));
memcacheditem item = mcc.gets("key1");
system.out.println("gets: value=" + item.getvalue() + ",casunique:"+item.getcasunique());
system.out.println("set: " + mcc.set("key1", "value1_1"));
system.out.println("cas: " + mcc.cas("key1", "value1_2", item.getcasunique())); //必須false
system.out.println("getmulti:" + mcc.getmulti(new string[]{"key1","key2","key3"}));
}
這個标題不好取,因為是我自己的想法,還需要大家多提意見,一起讨論。想叫“建議代碼”或者“推薦代碼”,覺得不合适,還是先叫“我的代碼”吧,呵呵。
1. 在原始用戶端上層,根據業務需求封裝memcachedservice(或叫memcachedclient),負責緩存功能的包裝。如:你的業務隻需要add,set,get,gets,cas,delete業務,那就隻封裝這幾個功能。這樣做的好處是,屏蔽了各種用戶端的api差異,讓你的業務系統與用戶端實作解耦合,如果你以後需要換用戶端實作,對你的業務系統不會照成影響。
2. 一般不要直接采用new的方式在你的代碼中顯示使用memcached用戶端實作,應該采用單例的方式使用memcached用戶端實作,或者使用spring的singleton方式配置。memcached用戶端實作是線程安全的。
3. memcached用戶端一般都需要大量的配置,考慮擴充和配置修改,應該把參數設定設計為可配置的,可以寫到propertis配置檔案中或是使用spring進行配置。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
/**
* memcached 常用功能接口定義,用于業務層直接使用,屏蔽各種用戶端實作的api差異,實作解耦用戶端與業務系統的目的
* 無過期時間和flags支援,無append,prepend,replace,incr,decr等操作
*
* @author zhangpu
*/
public interface memcachedclientservice {
string get(string key);
cacheitem gets(string key);
boolean add(string key, string value);
boolean set(string key, string value);
boolean cas(string key, string value, long unique);
boolean delete(string key)
boolean flushall();
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
public class cacheitem {
private string key;
private string value;
private long unique;
public cacheitem() {
super();
public cacheitem(string key, string value, long unique) {
this.key = key;
this.value = value;
this.unique = unique;
public string getkey() {
return key;
public void setkey(string key) {
public string getvalue() {
return value;
public void setvalue(string value) {
public long getunique() {
return unique;
public void setunique(long unique) {
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
* memcached for java用戶端緩存服務實作
*
public class memcachedclientjava implements memcachedclientservice {
memcachedclient mmc = memcachedclientfactory.getinstance();
public boolean add(string key, string value) {
return mmc.add(key, value);
public boolean cas(string key, string value, long unique) {
return mmc.cas(key, value, unique);
public string get(string key) {
return (string) mmc.get(key);
public cacheitem gets(string key) {
memcacheditem item = mmc.gets(key);
return new cacheitem(key, (string) item.getvalue(), item.getcasunique());
public boolean set(string key, string value) {
return mmc.set(key, value);
public boolean delete(string key) {
return mmc.delete(key);
public boolean flushall() {
return mmc.flushall();
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
* memcachedclient 單例(jdk1.5以上)
public class memcachedclientfactory extends configurableconstants{
private static volatile memcachedclient mmc;
init("memcached-client.properties");
//{ "localhost:11211", "localhost:11212", "localhost:11213" };
string[] servers = getproperty("memcached-servers","").split(",");
integer[] weights = null;
string weightscfg = getproperty("memcached-weights","");
if(weightscfg != null){
string[] wcfg = weightscfg.split(",");
weights = new integer[wcfg.length];
for (int i = 0; i < weights.length; i++) {
weights[i] = integer.valueof(wcfg[i]);
}
}else{
weights = new integer[servers.length];
weights[i] = 1;
}
pool.setinitconn(getproperty("memcached-initconn",5));
pool.setminconn(getproperty("memcached-minconn",5));
pool.setmaxconn(getproperty("memcached-maxconn",250));
private memcachedclientfactory() {
public static memcachedclient getinstance() {
if (mmc == null) {
synchronized (memcachedclient.class) {
if (mmc == null) {
mmc = new memcachedclient();
}
return mmc;
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
* 通過 properties 檔案配置設定常量基類 負責加載和讀取 properties 屬性檔案并提供通路的靜态工具方法
*
* @author zhangpu
*/
public class configurableconstants {
protected static log logger = logfactory.getlog(configurableconstants.class);
protected static properties p = new properties();
protected static void init(string propertyfilename) {
inputstream in = null;
try {
in = configurableconstants.class.getclassloader().getresourceasstream(propertyfilename);
if (in != null)
p.load(in);
} catch (ioexception e) {
logger.error("load " + propertyfilename + " into constants error!");
} finally {
if (in != null) {
try {
in.close();
} catch (ioexception e) {
logger.error("close " + propertyfilename + " error!");
}
}
}
}
protected static string getproperty(string key, string defaultvalue) {
return p.getproperty(key, defaultvalue);
protected static int getproperty(string key, int defaultvalue) {
return integer.parseint(getproperty(key, ""));
} catch (exception e) {
return defaultvalue;
memcached-client.properties
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZukHcvN2Xu92Yp9CXzV2Zh1WavwVbvNmLllXZ0lmL5x2bvNWYvw1LcpDc0RHaiojIsJye.gif)
memcached-client.properties
memcached-servers=localhost:11211,localhost:11212,localhost:11213
memcached-weights=3,3,2
memcached-initconn=5
memcached-minconn=5
memcached-maxconn=250
後續提供性能測試,spring整合,版本差異測試,及其它用戶端對比。