JAVA Memcached 安装与简单实战(windows)

时间:2023-01-20 20:46:03

 首先下载memcached的windows版本和java客户端jar包,目前最新版本是memcached-1.2.1-win32.zip和java_memcached-release_2.6.3.zip,分别解压后即可!首先是安装运行memcached服务器,我们将memcached-1.2.1-win32.zip解压后改名memcached放到e盘,进入其目录,然后运行如下命令: 
e:\cd memcached

e:\memcached >memcached.exe -d install -l 127.0.0.1 -m 1024 -c 2048

打开服务列表,可以看到memcached已经在上面可,如果没有启动,则手动启动一下。

JAVA Memcached 安装与简单实战(windows)


或者命令启动e:\memcached >memcached.exe  -d start 

启动完毕可以关闭cmd窗口



  memcached.exe -d install -l 127.0.0.1 -m 1024 -c 2048:是安装在本机,分配1024M内存,使用默认端口11211,允许连接数量2028和-d以守护进行运行。执行完毕后,我们就可以在任务管理器中见到memcached.exe这个进程了。


使用telnet命令 验证缓存服务器是否可用。

JAVA Memcached 安装与简单实战(windows)

开始什么都不显示,回车后输入命令  stats  查看统计信息,如下图,说明服务器运作正常。

JAVA Memcached 安装与简单实战(windows)

三、参数介绍

1、    以上的安装和启动给了一些参数,在安装时可设置如下参数:

   -p 设置端口号(默认不设置为: 11211)
   -l 绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)
   -d 独立进程运行:
   -d start 启动memcached服务
   -d restart 重起memcached服务
   -d stop|shutdown 关闭正在运行的memcached服务
   -d install 安装memcached服务
   -d uninstall 卸载memcached服务
   -u 绑定使用指定用于运行进程
   -m 允许最大内存用量,单位M (默认: 64 MB)
   -P 将PID写入文件,可以使得后边进行快速进程终止,需要与-d 一起使用
   -M 内存耗尽时返回错误,而不是删除项
   -c 最大同时连接数,默认是1024
   -f 块大小增长因子,默认是1.25
   -n 最小分配空间,key+value+flags默认是48
   -h 显示帮助

如:“memcached -d install -l 127.0.0.1 -m 1024 -c 2048 -p 22222”




好了,我们的服务器已经正常运行了,

接下来我们编写一个工具类MemcachedUtils.java。里面封装了一些memcached的方法,这些方法都是基于 java_memcached-release2.6.3.jar进行包装的, 使用它与spring整合可以方便我们在项目中使用。

本工具类的原作者是:http://blog.csdn.net/yin_jw/article/details/32331453

程序如下: Java代码  JAVA Memcached 安装与简单实战(windows)
  1. package com.test.utils;

    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.lang.management.ManagementFactory;
    import java.lang.management.RuntimeMXBean;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    import org.apache.log4j.Logger;

    import com.danga.MemCached.MemCachedClient;

    public class MemcachedUtils {
    private static final Logger logger = Logger.getLogger(MemcachedUtils.class);
    private static MemCachedClient cachedClient;
    static {
    if (cachedClient == null)
    cachedClient
    = new MemCachedClient("memcachedPool");//注入的是spring-memcached中的实例
    }

    private MemcachedUtils() {}

    /**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @return
    */
    public static boolean set(String key, Object value) {
    return setExp(key, value, null);
    }

    /**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    public static boolean set(String key, Object value, Date expire) {
    return setExp(key, value, expire);
    }

    /**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    private static boolean setExp(String key, Object value, Date expire) {
    boolean flag = false;
    try {
    flag
    = cachedClient.set(key, value, expire);
    }
    catch (Exception e) {
    // 记录Memcached日志
    MemcachedLog.writeLog("Memcached set方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
    }
    return flag;
    }

    /**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @return
    */
    public static boolean add(String key, Object value) {
    return addExp(key, value, null);
    }

    /**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    public static boolean add(String key, Object value, Date expire) {
    return addExp(key, value, expire);
    }

    /**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    private static boolean addExp(String key, Object value, Date expire) {
    boolean flag = false;
    try {
    flag
    = cachedClient.add(key, value, expire);
    }
    catch (Exception e) {
    // 记录Memcached日志
    MemcachedLog.writeLog("Memcached add方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
    }
    return flag;
    }

    /**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @return
    */
    public static boolean replace(String key, Object value) {
    return replaceExp(key, value, null);
    }

    /**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    public static boolean replace(String key, Object value, Date expire) {
    return replaceExp(key, value, expire);
    }

    /**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    *
    @param key
    * 键
    *
    @param value
    * 值
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    private static boolean replaceExp(String key, Object value, Date expire) {
    boolean flag = false;
    try {
    flag
    = cachedClient.replace(key, value, expire);
    }
    catch (Exception e) {
    MemcachedLog.writeLog(
    "Memcached replace方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
    }
    return flag;
    }

    /**
    * get 命令用于检索与之前添加的键值对相关的值。
    *
    *
    @param key
    * 键
    *
    @return
    */
    public static Object get(String key) {
    Object obj
    = null;
    try {
    obj
    = cachedClient.get(key);
    }
    catch (Exception e) {
    MemcachedLog.writeLog(
    "Memcached get方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
    }
    return obj;
    }

    /**
    * 删除 memcached 中的任何现有值。
    *
    *
    @param key
    * 键
    *
    @return
    */
    public static boolean delete(String key) {
    return deleteExp(key, null);
    }

    /**
    * 删除 memcached 中的任何现有值。
    *
    *
    @param key
    * 键
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    public static boolean delete(String key, Date expire) {
    return deleteExp(key, expire);
    }

    /**
    * 删除 memcached 中的任何现有值。
    *
    *
    @param key
    * 键
    *
    @param expire
    * 过期时间 New Date(1000*10):十秒后过期
    *
    @return
    */
    private static boolean deleteExp(String key, Date expire) {
    boolean flag = false;
    try {
    flag
    = cachedClient.delete(key, expire);
    }
    catch (Exception e) {
    MemcachedLog.writeLog(
    "Memcached delete方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
    }
    return flag;
    }

    /**
    * 清理缓存中的所有键/值对
    *
    *
    @return
    */
    public static boolean flashAll() {
    boolean flag = false;
    try {
    flag
    = cachedClient.flushAll();
    }
    catch (Exception e) {
    MemcachedLog.writeLog(
    "Memcached flashAll方法报错\r\n" + exceptionWrite(e));
    }
    return flag;
    }

    /**
    * 返回异常栈信息,String类型
    *
    *
    @param e
    *
    @return
    */
    private static String exceptionWrite(Exception e) {
    StringWriter sw
    = new StringWriter();
    PrintWriter pw
    = new PrintWriter(sw);
    e.printStackTrace(pw);
    pw.flush();
    return sw.toString();
    }

    /**
    *
    * @ClassName: MemcachedLog
    * @Description: Memcached日志记录
    *
    @author yinjw
    * @date 2014-6-18 下午5:01:37
    *
    */
    private static class MemcachedLog {
    private final static String MEMCACHED_LOG = "D:\\memcached.log";
    private final static String LINUX_MEMCACHED_LOG = "/usr/local/logs/memcached.log";
    private static FileWriter fileWriter;
    private static BufferedWriter logWrite;
    // 获取PID,可以找到对应的JVM进程
    private final static RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
    private final static String PID = runtime.getName();

    /**
    * 初始化写入流
    */
    static {
    try {
    String osName
    = System.getProperty("os.name");
    if (osName.indexOf("Windows") == -1) {
    fileWriter
    = new FileWriter(MEMCACHED_LOG, true);
    }
    else {
    fileWriter
    = new FileWriter(LINUX_MEMCACHED_LOG, true);
    }
    logWrite
    = new BufferedWriter(fileWriter);
    }
    catch (IOException e) {
    logger.error(
    "memcached 日志初始化失败", e);
    closeLogStream();
    }
    }

    /**
    * 写入日志信息
    *
    *
    @param content
    * 日志内容
    */
    public static void writeLog(String content) {
    try {
    logWrite.write(
    "[" + PID + "] " + "- [" + new SimpleDateFormat("yyyy年-MM月-dd日 hh时:mm分:ss秒").format(new Date().getTime()) + "]\r\n"
    + content);
    logWrite.newLine();
    logWrite.flush();
    }
    catch (IOException e) {
    logger.error(
    "memcached 写入日志信息失败", e);
    }
    }

    /**
    * 关闭流
    */
    private static void closeLogStream() {
    try {
    fileWriter.close();
    logWrite.close();
    }
    catch (IOException e) {
    logger.error(
    "memcached 日志对象关闭失败", e);
    }
    }
    }
    }
     spring-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:aop
    ="http://www.springframework.org/schema/aop"
    xmlns:tx
    ="http://www.springframework.org/schema/tx"
    xsi:schemaLocation
    ="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">


    <!-- 客户端:java_memcached-release_2.6.3 -->
    <bean id="memcachedPool" class="com.danga.MemCached.SockIOPool" factory-method="getInstance" init-method="initialize" lazy-init="false" destroy-method="shutDown">
    <constructor-arg>
    <value>memcachedPool</value>
    </constructor-arg>
    <!-- 可以设置多个memcached服务器 -->
    <property name="servers">
    <list>
    <value>127.0.0.1:11211</value>
    </list>
    </property>
    <!-- 每个服务器初始连接数 -->
    <property name="initConn">
    <value>20</value>
    </property>
    <!-- 每个服务器最小连接数 -->
    <property name="minConn">
    <value>20</value>
    </property>
    <!-- 每个服务器最大连接数 -->
    <property name="maxConn">
    <value>1000</value>
    </property>
    <!-- 主线程睡眠时间 -->
    <property name="maintSleep">
    <value>30000</value>
    </property>
    <!-- TCP/Socket的参数,如果是true在写数据时不缓冲,立即发送出去参数 -->
    <property name="nagle">
    <value>false</value>
    </property>
    <!-- 连接超时/阻塞读取数据的超时间是 -->
    <property name="socketTO">
    <value>3000</value>
    </property>
    </bean>

    <bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient" >
    <constructor-arg>
    <value>memcachedPool</value>
    </constructor-arg>
    </bean>

    </beans>


  2.      @RunWith(SpringJUnit4ClassRunner.class)
         @ContextConfiguration( "classpath:spring-memcached.xml")
         public class MemcachedTest {
    @Test
    public void testInsert(){
           User user = new User("honghong","19","man"); //存储对象要序列化
           MemcachedUtil.add("xxx",user);   
            }  
           @Test
        public void testGet(){
             //  User user = (User)MemcachedUtil.get("xiao");
               User user2 = (User)MemcachedUtil.get("xxx");
               System.out.println("输出:" + user2.getName()+user2.getAge()); 
            }  
          }
  3. 运行结果:   
  4.   
  5. com.danga.MemCached.MemCachedClient Tue Jan 31 16:28:39 CST 2012 - Storing with native handler...   
  6. com.danga.MemCached.MemCachedClient Tue Jan 31 16:28:39 CST 2012 - ++++ memcache cmd (result code): add hello 0 0 20   
  7. (NOT_STORED)   
  8. com.danga.MemCached.MemCachedClient Tue Jan 31 16:28:39 CST 2012 - ++++ data not stored in cache for key: hello   
  9. 输出: honghong19 

  其实呢 我们完全可以不用建memcachedutil这个类,在service层直接通过注解注入memCachedClient实例就可


2. 使用telnet进行连接

   现在我将在Windows7 下使用telnet连接安装好的memcached

    a. 开启Windows7 控制台,输入:   telnet  memcached_IP   memcached_PORT

 JAVA Memcached 安装与简单实战(windows)

b. 按Enter后,进入如下的页面:按Enter后,如果正常连接,会显示如此图所示的黑框框,输入任何东西都不会显现出来,看不到任何东西,这是因为Win7 中将telnet 回显功能关闭了,这时候需要手动设置回显。

JAVA Memcached 安装与简单实战(windows)

c. 对当前框同时按下  “CTRL ”和“]” 健,将进入如下页面:

JAVA Memcached 安装与简单实战(windows)

d. 输入  “set  localecho”,开启回显telnet回显功能

JAVA Memcached 安装与简单实战(windows)

e. 按下Enter键,进入telnet 交互界面,这时候用户可以看到自己的输入了,并且可以看到连接的memcached返回的交互信息:

[plain] view plaincopyprint?JAVA Memcached 安装与简单实战(windows)JAVA Memcached 安装与简单实战(windows)
  1. #向memcached存放一个key为variable、值为“louis”的键值对  
  2. set variable1 0 0 5  
  3.   
  4. #取出key为variable的值  
  5. get variable  

JAVA Memcached 安装与简单实战(windows)

至此,你就可以使用你的memcached啦。

3.   memcached 的操作指令

memcached本质上就是内存中的一个Map键值对集合,对于这个Map基本操作有以下几个:

  • 基本数据操作
    • set                设置指定键值对
    • add               若当前键值Key不存在,添加指定键值对
    • replace         若当前键值Key存在,更新当前Value值
    • get                获取指定键值对
    • delete           删除指定键值对
  • 高级数据操作
    • gets              获取键值key对应的值,返回信息中携带版本号
    • cas                指定版本号对键值key进行赋值,版本号不匹配,允许赋值
  • 缓存管理操作
    • stats             统计当前memcached 的数据信息。
    • flush_all       清空当前memcached 服务的所有缓存数据


基本数据操作:set、add、replace操作

     set、add、replace操作的格式相同,如下图所示:

JAVA Memcached 安装与简单实战(windows)

   注意:

    1. set、add、replace 操作指令需要输入两行才能完成,第一行是指令前段,第二行是value值;

    2. set、add、replace操作指定的字节数<length> 参数的大小要和第二行输入的字符串的个数保持完全相同,否则将会报:CLIENT_ERROR bad data chunk


1、set操作

    set 命令用于向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。

    JAVA Memcached 安装与简单实战(windows)

      如上图所示,如果set指令正确执行,memcached将会返回一个“STORED”信息,表示该指令被正确处理、已经将缓存数据放到了memcached中。


2. add操作

       向缓存中添加一个键值对,如果该键值key在缓存中尚未存在,则该键值对将添加到memcached缓存中;如果该键值已经存在了,那么保留以前的值,向客户端返回“NOT STORED”

JAVA Memcached 安装与简单实战(windows)


3. replace操作

    仅当键已经存在时,replace 命令才会替换缓存中的键。如果缓存中不存在键,那么您将从 memcached 服务器接受到一条NOT_STORED 响应。

JAVA Memcached 安装与简单实战(windows)

基本数据操作:get、delete操作

get和delete操作的格式比较简单,格式如下:

         <command>    <key>                             


4. get 操作

从缓存中根据key值取数据。如果缓存中有数据,这返回该数据;如果缓存中没有,则什么都不返回。

JAVA Memcached 安装与简单实战(windows)


5.  delete 操作 

   delete 命令用于删除 memcached 中的任何现有值。您将使用一个键调用 delete,如果该键存在于缓存中,则删除该值。如果不存在,则返回一条NOT_FOUND 消息。

JAVA Memcached 安装与简单实战(windows)



高级数据操作:gets、cas操作

6. gets操作

      gets操作和get操作的功能差不多,但它比get都返回一个信息:即这个键值对的“版本号”,版本号是使用64位的整形值表示的。memcached在以键值对进行存储的时候,会统计键值key的使用情况,每次以键值key进行增、删、改操作键值对的时候,该键值key代表的键值对的版本都会递增。

       操作形式为:

          gets    key                        

    操作如下:

JAVA Memcached 安装与简单实战(windows)


7. cas操作

         cas操作是(check and set)的缩写,在针对某个键值key设置对应的值的时候,要加上键值key目前的版本号。如果你指定的版本号比和键值Key的实际版本号不一致时,不会进行set操作,返回“EXISTS”提示。
       

        cas 的操作语法如下:

                      cas   key  flags   expiration_time  length   version            

JAVA Memcached 安装与简单实战(windows)



管理操作:stats、flush_all 操作

8.   stats 

         stats 是statistics单词的拼写,即统计的意思。该指令攻击当前memcached服务的各种指标。这些指标跟memcached 的性能和工作状况紧密相关。

JAVA Memcached 安装与简单实战(windows)


9. flush_all

    flus_all 指令用于清空memcached中所有的键值对。

JAVA Memcached 安装与简单实战(windows)



4.   操作memcached 的客户端

java如果想要与memcached联合使用的话,需要使用memcached的客户端,这是网友们的叫法。其实就是jar包。这些jar包帮我们封装好了一些方法,避免我们自己再去实现复杂的操作了。

目前我看到有三个客户端:

    • java_memcached-release     --->:danga的,我也不知道这是什么组织……,但这个客户端比较老牌的了,应用的还是挺广泛的
    • alisoft-xplatform-asf-cache  --->:阿里的
    • XMemcached                      --->:oschina上看到的,貌似是纯国产啊,应用的还是挺广泛的~