发表于: 2019-11-24 23:35:08
1 1013
今天完成的事:
1、学习Memcached缓存。
首先就是理解Memcached、memcache、memcached三者的区别。
Memcached:指的是Memcached服务器,就是独立运行Memcached的后台服务器,用于缓存数据的容器。
且Memcached是一个高性能分布式的内存对象缓存系统,通过缓存数据库查询结果,减少访问数据库次数,减少负载压力,提高动态web应用的性能。
memcache、memcached:是Memcached的客户端,通过两者可以访问Memcached服务器,两者只有微小差异。memcached要多些守护进程的操作方法,性能更好些。
Memcached适合存储的数据:
(1)访问较为频繁的数据,安全性差的数据,丢失无所谓的数据。
(2)数据更新,比较繁琐的数据,比如用户的在线状态。
(3)数据的单个键值对不能太大,不要超过1MB的数据。
2、java连接Memcached服务。
首先下载memcached客户端,下载地址: http://static.runoob.com/download/memcached-win64-1.4.4-14.zip
因为1.4.5版本之前memcached可以作为一个服务器安装,安装方便,所以这里下载64位系统1.4.4版本。
只需要将下载的压缩包解压,而后cd到文件夹下“memcached.exe -d install”直接安装即可。
使用“memcached.exe -h”可以查看相关参数,因为默认IP范围太大,尝试进行修改。
修改配置需如下所示,
打开注册表,找到对对应的注册表,修改ImagePath参数,这里改为本机 127.0.0.1:11314 端口,内存128MB。
使用start、stop命令进行memcached服务的启闭。
可以在任务管理器中查看memcached服务的运行。
如果需要卸载的话,按如下即可。
java连接Memcached服务,有三种方式,这里选用SpyMemcached方式。
首先添加spymemcached的jar包,查看的都是说下载jar包导入,搜了好久发现有个说是可以使用谷歌的一个依赖,于是maven中心库中搜索,分别尝试了两种jar包,
两个jar包都可以单独使用。但是测试类中导入的类是一样的。
本来以为两个jar包会有冲突,结果并没有,在依赖树里,两个jar包并列。这里使用的net.spy的jar包。
上面说了修改了IP以及端口,正确才能正常存储,使用其他的都会报错异常。也算是验证了修改有效。
3、memcached命令。
set、add、replace三个命令返回值为boolean,set是设置数据,相当于add加replace,add是添加数据,key不能相同,replace是修改数据,key必须是存在的,修改其value。
append、prepend命令都是给存在的key追加value数据,只是位置不同,一前一后。
其中set命令,相关参数如下,主要是key、exptime、value。
命令中主要是CAS命令需要重点说下,CAS主要是为了分布式环境下更新的一致性问题,每次更新都需要指定更新的key的cas_token,可以使用gets命令得到,注意是命令后有“s”。CAS仅在当前客户端最后一次取值后,该key对应的值没有被其他客户端修改的情况下,才能将值写入,检查则是通过cas_token参数进行,这个参数是memcached指定给已存在的元素的一个唯一的64位值。
cas_token也就是key的版本标识,每当value被修改时,其key的cas_token就会被更新,加一,保证当前只有一个客户端对memcached进行操作,没有操作成功,就说明有其他客户端在操作,需要利用gets命令获得当前的cas_token,然后继续操作。
相应命令代码如下:
import net.spy.memcached.CASResponse;
import net.spy.memcached.CASValue;
import net.spy.memcached.MemcachedClient;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class MemcacheTest {
private static Logger logger = Logger.getLogger(MemcacheTest.class);
MemcachedClient mcc;
@Before
public void before(){
try {
// 本地连接 Memcached 服务
mcc = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11314));
System.out.println("本地连接 Memcached 服务:成功!");
} catch (IOException e) {
// 不要使用捕捉自带的打印信息,容易锁死空间
// e.printStackTrace();
// 使用logger打印日志
logger.error("连接失败!出现异常:" + e);
// 或者直接 e.getMessage() 输出,但是e.getMessage()信息可能不全
System.out.println("连接失败!出现异常:" + e.getMessage());
}
}
@After
public void after(){
// 关闭连接
mcc.shutdown();
System.out.println("关闭连接");
}
// 设置数据
@Test
public void set(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 添加数据,key不能相同
@Test
public void add(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 添加原有key
fo = mcc.add("aaa", 900, "memcached");
// 打印状态,false
System.out.println("添加原有key,存储状态:" + fo.get());
// 添加新key
fo = mcc.add("111", 900, "222");
// 打印状态,true
System.out.println("添加新key,存储状态:" + fo.get());
// 输出
System.out.println("新key输出值 - " + mcc.get("111"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 修改数据,key需存在相同key名称
@Test
public void replace(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 原有key修改值
fo = mcc.replace("aaa", 900, "666");
// 输出 原有key修改值 方法后的状态,true
System.out.println("添加原有key,存储状态:" + fo.get());
// 获取键对应的值
System.out.println("原有key输出值 - " + mcc.get("aaa"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 对存在的key进行 后部 的数据添加操作
@Test
public void append(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 对存在的key进行数据添加操作
fo = mcc.append("aaa", " 222");
// 输出状态
System.out.println("存储状态:" + fo.get());
// 获取键对应的值
System.out.println("输出值 - " + mcc.get("aaa"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 对存在的key进行 前部 的数据添加操作
@Test
public void prepend(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 对存在的key进行数据添加操作
fo = mcc.prepend("aaa", "222 ");
// 输出执行 set 方法后的状态
System.out.println("存储状态:" + fo.get());
// 获取键对应的值
System.out.println("输出值 - " + mcc.get("aaa"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 对存在的key使用 cas方法 来更新数据
@Test
public void CAS(){
try {
// 存储数据
Future fo = mcc.set("rrr", 900, "ccc");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("rrr"));
// 通过 gets 方法获取 CAS token(令牌)
CASValue casValue = mcc.gets("rrr");
// 输出 CAS token(令牌) 值
System.out.println("CAS token - " + casValue);
// 输出 CAS token(令牌) 对应的 数字值
System.out.println("CAS token 数字 - " + casValue.getCas());
// 尝试使用cas方法来更新数据
CASResponse casresp = mcc.cas("rrr", casValue.getCas(), 900, "333");
// 输出 CAS 响应信息
System.out.println("CAS响应信息 - " + casresp);
// 输出值
System.out.println("cas更新,输出值 - " + mcc.get("rrr"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 对存在的key进行数据 删除 操作
@Test
public void delete(){
try {
// 存储数据
Future fo = mcc.set("aaa", 900, "bbb");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 对存在的key进行数据删除操作
fo = mcc.delete("aaa");
// 输出执行 delete 方法后的状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
// 对存储的数据,十进制的32位无符号整数,进行 自增、自减 操作
@Test
public void IncrDecr(){
try {
// 存储数据
Future fo = mcc.set("number", 900, "11111");
// 查看存储状态
System.out.println("存储状态:" + fo.get());
// 输出值
System.out.println("输出值 - " + mcc.get("aaa"));
// 自增并输出
System.out.println("自增并输出 - " + mcc.incr("number", 111));
// 自减并输出
System.out.println("自减并输出 - " + mcc.decr("number", 112));
} catch (InterruptedException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
} catch (ExecutionException e) {
logger.error("出现异常:" + e);
System.out.println("出现异常:" + e.getMessage());
}
}
}
明天计划的事:
1、学习Redis缓存。
2、进行压测对比。
遇到的问题:
无
收获:
1、学习Memcached缓存。
首先就是理解Memcached、memcache、memcached三者的区别。
2、java连接Memcached服务,选用SpyMemcached方式。
下载memcached客户端,下载地址: http://static.runoob.com/download/memcached-win64-1.4.4-14.zip
3、学习了memcached命令。
评论