書接上文:理論加實踐,談談我對memcached的學習感悟!
接近兩周的時間,終於將面向JAVA的memcached客戶端操作類封裝寫完。
現將當前的成果共享上來,希望有經驗的朋友能指點一二。
一、初衷
其實,java_memcached-release已經很完善了,並且使用起來非常方便
但是個人還是習慣將第三方的lib封裝起來,好處有二:首先可以為應用層與底層留下空間,增加靈活性;另外也可以根據具體的項目要求,對方法進行重載,增加友好性。
在對java_memcached-release進行封裝之前,有以下幾個主要目的:
- 支持配置文件,包括定義memcached服務器信息及連接池相關的初始化參數。這對於一個項目來說,是必須的,否則一旦對memcached服務器進行調整,或者需要改變連接池的某個參數,還要去修改JAVA文件,再重新編譯、打包,那就太兒戲了。
- 第一次對工具類進行初始化時,要對預先配置的各服務器進行檢測,如果無法連接,或者連接時間超過上限,則放棄該服務器。在java_memcached-release中,使用pool.setServers(String[]{"ServerA_IP:Port", "ServerB_IP:Port"})方式傳入備用的服務器信息,如果其中某個服務器無法連接,或連接時間過長,那么每次對該服務器進行操作時(比如:add),會等待相對長的時間,由於memcached內部采用分布式算法,並不是每次操作都會將任務指派給這台服務器,但偶爾一次漫長的等待還是非常不爽的,更與使用內存數據庫的初衷產生強烈反差。
- 是否啟用memcached的開關:這個也很主要,首先可以針對兩種情況對性能進行監控和對比,另外在生產環境下,對項目進行調試時,為了數據的一致性,也需要暫時關閉內存數據庫支持,待問題排除后再重新打開。
- 返回當前各服務器運行狀態的統計信息,源生的stats方法很全面,但輸出的參數順序很不適應,如果能顯示中文就更好了,因為日后的項目維護人員不一定能了解每個英文參數的確切含義。
- 可以按服務器和Slab對其中的item進行遍歷,然后可以對選定的item進行查詢或者刪除。雖說這種操作不被推薦,但在對項目進行Debug時還是非常需要的
- 按照習慣對某些方法進行重載,比如add,源生的超期參數是Date,但有些時候還是感覺傳入一個天數更方便一些。
- 滿足一定性能要求的構造方式以及初始化邏輯
在進行封裝時,完全遵循了以上的七個原則,至於最后一條,還需要等待時間去驗證
二、依賴
- memcached-1.2.1-win32(memcached.exe) 最主要的
- com.danga.MemCached(java_memcached-release_2.6.6.jar) 最關鍵的,面向JAVA的memcached客戶端lib
- org.dom4j(dom4j-1.6.1.jar) 用於加載並解析配置文件(xml格式)
- org.apache.commons.net.telnet(commons-net-3.2.jar) 使用Telnet方式對服務器進行檢測,以確認是否可用
如果想要memcached的支持自動壓縮功能,也可以使用java_memcached-release_1.6.jar,其用法與2.6.6全部一致,但不要同時使用這兩個版本,以免發生意外問題。
三、配置文件
文件名稱:MemCachedConfig.xml
存放位置:src/
文件內容:
<?xml version="1.0" encoding="UTF-8"?>
<!-- ***** memcached數據庫配置文件 ***** author : 網無忌(netwild) email : inetwild@gmail.com qq : 52100641 *********************************** -->
<MemCachedConfig>
<!-- Enabled : 是否啟用memcached內存數據庫選項 可選值 : true - 啟用; false - 停用 -->
<Enabled>true</Enabled>
<!-- Servers : 可用的memcached服務器列表,各服務器根據weight(負載權重值)實現分布式任務均衡 注意 : 各memcached服務器負載權重值的最大公約數最好為1,可在一定程度上簡化其內部的負載均衡算法 規則 : <Server host="memcached服務器IP或域名" post="memcached服務端口(默認11211)" weight="負載權重值" /> -->
<Servers>
<Server host="192.168.1.10" post="11211" weight="2" />
<Server host="192.168.1.11" post="11211" weight="1" />
<Server host="192.168.1.12" post="11211" weight="1" />
</Servers>
<!-- Config : memcached數據庫配置選項 initConn : 初始連接數 minConn : 最小連接數 maxConn : 最大連接數 maxIdle : 連接最大空閑時間(毫秒) maintSleep : 主線程的維護周期(每隔多少秒維護一次連接池,0表示不啟用主線程) socketTO : 讀取操作的超時限制(毫秒) socketConnTO : 連接操作的超時限制(毫秒,0表示不限制) compressEnable : 是否啟用自動壓縮(該參數從java_memcached-release_2.6.1開始不再支持) compressThreshold : 超過指定大小(bytes)的數據都會被壓縮(該參數從java_memcached-release_2.6.1開始不再支持) -->
<Config>
<property name="initConn">5</property>
<property name="minConn">5</property>
<property name="maxConn">250</property>
<property name="maxIdle">21600000</property>
<property name="maintSleep">30</property>
<property name="socketTO">10000</property>
<property name="socketConnTO">0</property>
<property name="compressEnable">true</property>
<property name="compressThreshold">65536</property>
</Config>
</MemCachedConfig>
四、封裝好的memcached客戶端操作類
文件名稱:MemCached.java
存放位置:src.com.common
文件內容:
package com.common; import java.io.File; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedList; import java.util.List; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.net.telnet.TelnetClient; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; import com.danga.MemCached.MemCachedClient; import com.danga.MemCached.SockIOPool; /** * @category memcached內存數據庫操作類 * @author 網無忌(netwild) * @email inetwild@gmail.com * @qq 52100641 * @version 1.0 */
public class MemCached { //是否啟用MemCached內存數據庫
protected static boolean enUsed = true; //創建全局唯一的可實例化對象
protected static MemCached memCached = new MemCached(); //初始化MemCached客戶端對象
protected static MemCachedClient memClient = new MemCachedClient(); //定義MemCached服務器運行環境配置文件名稱
private static final String MemCachedConfigFile_NAME = "MemCachedConfig.xml"; //定義可用的MemCached服務器列表,用於分布式存儲
private static String[] serverListArr = new String[1]; //定義各MemCached服務器的負載權重列表,與服務器列表按先后順序對應
private static Integer[] weightListArr = new Integer[1];; //定義MemCached服務器運行環境表,配置文件中關於參數相關數據將保存到該表
private static Map<String, String> serverConfig; //定義MemCached服務器運行狀態表,用於保存各狀態的中文解釋
protected static HashMap<String, String> statsItems; //設置全局靜態參數,以下代碼在整個服務器運行周期內僅運行一次!
static { //初始化MemCached運行環境配置 //首先初始化各參數默認值,然后加載配置文件,遍歷其中的參數值並進行覆蓋。
initConfig(); if(enUsed){ //如果已啟用memcached緩存服務 //獲取socke連接池的實例對象
SockIOPool pool = SockIOPool.getInstance(); //設置可用的MemCached服務器信息,實現分布式存儲
pool.setServers(serverListArr); //設置各MemCached服務器的負載權重,根據可支配內存實現負載均衡
pool.setWeights(weightListArr); //設置初始連接數
pool.setInitConn(Integer.parseInt(serverConfig.get("initConn").toString())); //設置最小連接數
pool.setMinConn(Integer.parseInt(serverConfig.get("minConn").toString())); //設置最大連接數
pool.setMaxConn(Integer.parseInt(serverConfig.get("maxConn").toString())); //設置連接最大空閑時間
pool.setMaxIdle(Long.parseLong(serverConfig.get("maxIdle").toString())); //設置主線程的睡眠時間,每隔該時間維護一次各連接線程狀態
pool.setMaintSleep(Long.parseLong(serverConfig.get("maintSleep").toString())); //關閉nagle算法
pool.setNagle(false); //讀取操作的超時限制
pool.setSocketTO(Integer.parseInt(serverConfig.get("socketTO").toString())); //連接操作的超時限制,0為不限制
pool.setSocketConnectTO(Integer.parseInt(serverConfig.get("socketConnTO").toString())); //初始化連接池
pool.initialize(); //壓縮設置,超過指定大小的數據都會被壓縮 //從java_memcached-release_2.6.1開始已經不再支持內置的數據壓縮功能 //memClient.setCompressEnable(Boolean.parseBoolean(serverConfig.get("compressEnable").toString())); //memClient.setCompressThreshold(Long.parseLong(serverConfig.get("compressThreshold").toString()));
} } /** * @category 初始化MemCached運行環境配置 * @category 注:該方法在整個服務器周期內僅運行一次 */
protected static void initConfig(){ //初始化可用的MemCached服務器列表默認值(本機)
serverListArr[0] = "127.0.0.1:11211"; weightListArr[0] = 1; //初始化MemCached服務器運行環境表(默認值),當某參數未在配置文件中進行定義時,將使用該默認值
serverConfig = new HashMap<String, String>(){ private static final long serialVersionUID = 1L; { put("initConn", "5"); //設置初始連接數
put("minConn", "5"); //設置最小連接數
put("maxConn", "250"); //設置最大連接數
put("maxIdle", "21600000"); //設置連接最大空閑時間(6小時)
put("maintSleep", "30"); //設置主線程的睡眠時間(30秒)
put("socketTO", "10000"); //讀取操作的超時限制(10秒)
put("socketConnTO", "0"); //連接操作的超時限制(不限制)
put("compressEnable", "true"); //是否啟用自動壓縮(啟用)
put("compressThreshold", "65536"); //超過指定大小的數據都會被壓縮(64K)
} }; //開始讀取配置文件,並將其中的參數值向默認環境表中進行覆蓋
String filePath = Thread.currentThread().getContextClassLoader().getResource("MemCachedConfig.xml").getPath().substring(1); File file = new File(filePath.replaceAll("%20"," ")); try{ if(file.exists()){ //如果可以成功加載配置文件
SAXReader sr = new SAXReader(); Document doc = sr.read(file); Element Root = doc.getRootElement(); //獲得根節點
Element Enabled = (Element)Root.selectSingleNode("Enabled"); //獲得是否啟用memcached節點
Element Servers = (Element)Root.selectSingleNode("Servers"); //獲得可用的服務器列表父節點
Element Config = (Element)Root.selectSingleNode("Config"); //獲得運行環境參數列表父節點
enUsed = Boolean.parseBoolean(Enabled.getText()); //是否啟用memcached緩存服務
List<Element> serverDoms = Servers.elements(); //備用的服務器列表
List<Element> serverUsed = new ArrayList<Element>(); //經檢測,實際可用的服務器列表
TelnetClient telnet = new TelnetClient(); //初始化Telnet對象,用來檢測服務器是否可以成功連接
telnet.setConnectTimeout(5000); //連接超時:5秒
for(Element serverTmp : serverDoms){ try{ telnet.connect(serverTmp.attributeValue("host"), Integer.parseInt(serverTmp.attributeValue("post"))); //連接到服務器
telnet.disconnect(); //斷開連接
serverUsed.add(serverTmp); //連接成功,將服務器添加到實際可用列表
}catch(Exception e){} } int serverCount = serverUsed.size(); //經檢測,實際可用的服務器個數
if(serverCount == 0){ //沒有發現實際可用的服務器,返回
enUsed = false; return; } serverListArr = new String[serverCount]; //初始化服務器地址及端口號數組
weightListArr = new Integer[serverCount]; //初始化服務器負載權重數組
for(int ind=0; ind < serverCount; ind++){ //向服務器數組進行賦值
serverListArr[ind] = serverUsed.get(ind).attributeValue("host") + ":" + serverUsed.get(ind).attributeValue("post"); weightListArr[ind] = Integer.parseInt(serverUsed.get(ind).attributeValue("weight").toString()); } Object[] serverConfigArr = serverConfig.keySet().toArray(); //返回服務器運行環境參數列表,用於遍歷配置文件
for(Object cfgItem : serverConfigArr){ Node node = Config.selectSingleNode("//property[@name='" + cfgItem + "']"); //查找指定的參數節點
if(node == null) continue; //如果該參數節點不存在,則繼續查找下一個參數,該參數將采用默認值
Element configNode = (Element)node; serverConfig.put(cfgItem.toString(), configNode.getTextTrim()); //添加配置文件中定義的參數值
} } }catch(Exception e){ System.out.println(e.toString()); } //初始化MemCached服務器運行狀態表,對各狀態進行中文解釋
statsItems = new HashMap<String, String>(){ { put("pid", "MemCached服務進程ID"); put("version", "MemCached服務版本"); put("pointer_size", "MemCached服務器架構"); put("time", "服務器當前時間"); put("uptime", "服務器本次啟動以來,總共運行時間"); put("connection_structures", "服務器分配的連接結構數"); put("total_connections", "服務器本次啟動以來,累計響應連接總次數"); put("curr_connections", "當前打開的連接數"); put("limit_maxbytes", "允許服務支配的最大內存容量"); put("bytes", "當前已使用的內存容量"); put("bytes_written", "服務器本次啟動以來,寫入的數據量"); put("bytes_read", "服務器本次啟動以來,讀取的數據量"); put("total_items", "服務器本次啟動以來,曾存儲的Item總個數"); put("curr_items", "當前存儲的Item個數"); put("cmd_get", "服務器本次啟動以來,執行Get命令總次數"); put("get_hits", "服務器本次啟動以來,Get操作的命中次數"); put("get_misses", "服務器本次啟動以來,Get操作的未命中次數"); put("cmd_set", "服務器本次啟動以來,執行Set命令總次數"); } }; } /** * @category 保護型構造方法,不允許實例化! */
protected MemCached() { } /** * @category 操作類入口:獲取唯一實例. * * @return MemCached對象 */
public static MemCached getInstance() { return memCached; } /** * @category 返回是否已經啟用memcached內存服務器 * * @return boolean */
public static boolean used(){ return enUsed; } /** * @category 插入新記錄. * @category 前提:記錄的Key在緩存中不存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @return boolean 操作結果 */
public boolean add(String key, Object value) { if(!enUsed){ return false; }else{ return memClient.add(key, value); } } /** * @category 插入新記錄並設置超時日期 * @category 前提:記錄的Key在緩存中不存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDate 超時日期 * @return boolean 操作結果 */
public boolean add(String key, Object value, Date expiryDate) { if(!enUsed){ return false; }else{ return memClient.add(key, value, expiryDate); } } /** * @category 插入新記錄並設置超時天數 * @category 前提:記錄的Key在緩存中不存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDays 超時天數 * @return boolean 操作結果 */
public boolean add(String key, Object value, int expiryDays){ if(!enUsed){ return false; }else{ Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.add(Calendar.DATE,expiryDays); //增加天數
return memClient.add(key, value, calendar.getTime()); } } /** * @category 插入新記錄或更新已有記錄 * @category 解釋:記錄的Key在緩存中不存在則插入;否則更新 * @param key 記錄的主鍵 * @param value 記錄的內容 * @return boolean 操作結果 */
public boolean set(String key, Object value){ if(!enUsed){ return false; }else{ return memClient.set(key, value); } } /** * @category 插入新記錄或更新已有記錄,並設置超時日期 * @category 解釋:記錄的Key在緩存中不存在則插入;否則更新 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDate 超時日期 * @return boolean 操作結果 */
public boolean set(String key, Object value, Date expiryDate){ if(!enUsed){ return false; }else{ return memClient.set(key, value, expiryDate); } } /** * @category 插入新記錄或更新已有記錄,並設置超時天數 * @category 解釋:記錄的Key在緩存中不存在則插入;否則更新 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDate 超時天數 * @return boolean 操作結果 */
public boolean set(String key, Object value, int expiryDays){ if(!enUsed){ return false; }else{ Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.add(Calendar.DATE,expiryDays); //增加天數
return memClient.set(key, value, calendar.getTime()); } } /** * @category 更新已有記錄 * @category 前提:記錄的Key在緩存中已經存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @return boolean 操作結果 */
public boolean replace(String key, Object value) { if(!enUsed){ return false; }else{ return memClient.replace(key, value); } } /** * @category 更新已有記錄,並設置超時日期 * @category 前提:該值在緩存中已經存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDate 超時日期 * @return boolean 操作結果 */
public boolean replace(String key, Object value, Date expiryDate) { if(!enUsed){ return false; }else{ return memClient.replace(key, value, expiryDate); } } /** * @category 更新已有記錄,並設置超時天數 * @category 前提:該值在緩存中已經存在 * @param key 記錄的主鍵 * @param value 記錄的內容 * @param expiryDays 超時天數 * @return boolean 操作結果 */
public boolean replace(String key, Object value, int expiryDays) { if(!enUsed){ return false; }else{ Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.add(Calendar.DATE,expiryDays); //增加天數
return memClient.replace(key, value, calendar.getTime()); } } /** * @category 返回單條記錄 * * @param key 記錄的主鍵 * @return 記錄的內容 */
public Object get(String key) { if(!enUsed){ return null; }else{ return memClient.get(key); } } /** * @category 返回多條記錄 * * @param keys 記錄的主鍵數組 * @return Map<String, Object> 多條記錄的內容 */
public Map<String, Object> get(String[] keys) { if(!enUsed){ return null; }else{ return memClient.getMulti(keys); } } /** * @category 刪除記錄 * @category 執行該方法之后,使用stats的統計結果會同步更新 * @param key 記錄的主鍵 * @return 操作結果 */
public boolean delete(String key){ if(!enUsed){ return false; }else{ return memClient.delete(key); } } /* * **************************************************************************************************************** * 下面的6個方法都是為了對memcached服務器進行監控及管理所用的,可能對服務器造成阻塞,所以除Debug以外,不推薦使用! */
/** * @category 清空全部緩存數據。*慎用!! * @category 執行該方法之后,使用stats的統計結果不會馬上發生變化,每get一個不存在的item之后,該item的值才會被動清空 * @return 操作結果 */
public boolean flushAll(){ if(!enUsed){ return false; }else{ return memClient.flushAll(); } } /** * @category 返回可用的服務器列表 * @return 數組(服務器地址:端口) */
public String[] servers(){ if(!enUsed) return null; return serverListArr; } /** * @category 返回所有緩存服務器當前的運行狀態 * @return * * Map * |-- Key : ServerName01, Value : LinkedHashMap * | |-- Key : statName01, Value : statValue * | |-- ... * | * |-- Key : ServerName02, Value : LinkedHashMap * | |-- Key : statName01, Value : statValue * | |-- ... * | * |-- ... * */
public Map<String,LinkedHashMap<String, String>> stats(){ if(!enUsed) return null; Map<String,LinkedHashMap<String, String>> retMap = new HashMap<String,LinkedHashMap<String, String>>(); for(String server : serverListArr){ LinkedHashMap<String, String> serverStats = this.stats(server); retMap.put(server, serverStats); } return retMap; } /** * @category 返回指定服務器當前的運行狀態 * @param server 服務器地址:端口 * * 優化: 參數名稱中文顯示 * 優化: 毫秒數轉換為小時 * 優化: 字節數轉換為MB或KB * 優化: UNIX時間戳轉換為標准時間 * 優化: 參數顯示順序更加直觀 * * @return LinkedHashMap<String, String> 可對Map進行有序遍歷 * */
public LinkedHashMap<String, String> stats(String server){ if(!enUsed) return null; LinkedHashMap<String, String> retMap = new LinkedHashMap<String, String>(); Map<String, Map<String, String>> statsList = memClient.stats(new String[]{server}); //System.out.println(memClient.stats().toString());
DecimalFormat format = new DecimalFormat("0.0"); for(Object serverTitle : statsList.keySet().toArray()){ Map<String, String> serverStats = (Map<String, String>)statsList.get(serverTitle); retMap.put(statsItems.get("pid"), serverStats.get("pid").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("version"), serverStats.get("version").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("pointer_size"), serverStats.get("pointer_size").replaceAll("\\r\\n", "") + "位"); retMap.put(statsItems.get("time"), new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(Long.parseLong(serverStats.get("time").replaceAll("\\r\\n", "")) * 1000)).toString()); retMap.put(statsItems.get("uptime"), format.format(Double.parseDouble(serverStats.get("uptime").replaceAll("\\r\\n", ""))/(60*60)) + "小時"); retMap.put(statsItems.get("connection_structures"), serverStats.get("connection_structures").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("total_connections"), serverStats.get("total_connections").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("curr_connections"), serverStats.get("curr_connections").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("limit_maxbytes"), format.format(Double.parseDouble(serverStats.get("limit_maxbytes").replaceAll("\\r\\n", ""))/(1024*1024)) + "MB"); retMap.put(statsItems.get("bytes"), format.format(Double.parseDouble(serverStats.get("bytes").replaceAll("\\r\\n", ""))/(1024*1024)) + "MB"); retMap.put(statsItems.get("bytes_written"), format.format(Double.parseDouble(serverStats.get("bytes_written").replaceAll("\\r\\n", ""))/(1024)) + "KB"); retMap.put(statsItems.get("bytes_read"), format.format(Double.parseDouble(serverStats.get("bytes_read").replaceAll("\\r\\n", ""))/(1024)) + "KB"); retMap.put(statsItems.get("total_items"), serverStats.get("total_items").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("curr_items"), serverStats.get("curr_items").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("cmd_get"), serverStats.get("cmd_get").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("get_hits"), serverStats.get("get_hits").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("get_misses"), serverStats.get("get_misses").replaceAll("\\r\\n", "")); retMap.put(statsItems.get("cmd_set"), serverStats.get("cmd_set").replaceAll("\\r\\n", "")); } return retMap; } /** * @category 返回指定服務器及Slab中當前使用的item列表 * @param server 服務器地址:端口 * @param slab SlabId * @param counter 最多顯示items條數 * @return
*/
public LinkedList<String> items(String server, int slab, int counter){ if(!enUsed) return null; LinkedList<String> ret = new LinkedList<String>(); Map<String, String> itemsKey = memClient.statsCacheDump(new String[]{server}, slab, counter).get(server); for(Object key : itemsKey.keySet().toArray()){ ret.add(key.toString()); } return ret; } /** * @category 返回指定服務器當前使用的SlabsID列表 * @param server 服務器地址:端口 * @return
*/
public LinkedList<Integer> slabs(String server){ if(!enUsed) return null; LinkedList<Integer> slabsId = new LinkedList<Integer>(); Map<String, String> itemsMap = memClient.statsItems(new String[]{server}).get(server); Object[] itemsArr = itemsMap.keySet().toArray(); for(int i=0, len=itemsArr.length; i<len; i+=2){ slabsId.add(Integer.parseInt(itemsArr[i].toString().split(":")[1])); } return slabsId; } /* * 上面的6個方法都是為了對memcached服務器進行監控及管理所用的,可能對服務器造成阻塞,所以除Debug以外,不推薦使用! * **************************************************************************************************************** */
/** * 使用示例 */
public static void main(String[] args) { //初始化memcached操作類對象
MemCached cache = MemCached.getInstance(); //驗證memcached服務是否已啟用
if(!cache.used()){ System.out.println("memcached服務未啟用!"); return; } //插入新記錄
System.out.println("開始插入新記錄(add):\r\n==================================="); System.out.println("keyTest01:" + cache.add("keyTest01", "keyTest01Content")); System.out.println("keyTest02:" + cache.add("keyTest02", "keyTest02Content")); System.out.println("插入新記錄操作完成\r\n==================================="); //讀取單條記錄
System.out.println("讀取單條記錄(get):\r\n==================================="); System.out.println("keyTest01:" + cache.get("keyTest01")); System.out.println("keyTest02:" + cache.get("keyTest02")); System.out.println("讀取單條記錄操作完成\r\n==================================="); //讀取多條記錄
System.out.println("讀取多條記錄(add):\r\n==================================="); System.out.println("keyTest01、keyTest02:" + cache.get(new String[]{"keyTest01", "keyTest02"})); System.out.println("讀取多條記錄操作完成\r\n==================================="); //修改記錄值
System.out.println("修改記錄值(replace):\r\n==================================="); System.out.println("keyTest01:" + cache.get("keyTest01")); System.out.println("keyTest01:" + cache.replace("keyTest01", "keyTest01ContentReplace!")); System.out.println("keyTest01:" + cache.get("keyTest01")); System.out.println("修改記錄值操作完成\r\n==================================="); //添加或修改記錄
System.out.println("添加或修改記錄(set):\r\n==================================="); System.out.println("keyTest03:" + cache.set("keyTest03", "keyTest03Content")); System.out.println("keyTest03:" + cache.get("keyTest03")); System.out.println("keyTest03:" + cache.set("keyTest03", "keyTest03ContentReplace!")); System.out.println("keyTest03:" + cache.get("keyTest03")); System.out.println("添加或修改記錄操作完成\r\n==================================="); //刪除記錄
System.out.println("刪除記錄(delete):\r\n==================================="); System.out.println("keyTest01:" + cache.delete("keyTest01")); System.out.println("keyTest02:" + cache.delete("keyTest02")); System.out.println("keyTest03:" + cache.get("keyTest03")); System.out.println("keyTest03:" + cache.delete("keyTest03")); System.out.println("keyTest03:" + cache.get("keyTest03")); System.out.println("修改記錄值操作完成\r\n==================================="); //打印當前的服務器參數及統計信息
System.out.println("服務器參數及統計信息(stats):\r\n==================================="); Map statsList = cache.stats(); for(Object server : statsList.keySet().toArray()){ System.out.println("-------------------------\r\n服務器:" + server + " : \r\n-------------------------"); LinkedHashMap serverStats = (LinkedHashMap)statsList.get(server); for(Object statKey : serverStats.keySet().toArray()){ System.out.println(statKey + " : " + serverStats.get(statKey)); } } } }
五、OVER!