概述 :
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。Memcached基于内存的key-value存储,
用来存储小块的任意数据,这些数据可以是数据库调用、API调用或者是页面渲染的结果。
通过Memcached缓存数据库查询结果,可以有效地减少数据库访问次数,进而提高动态Web应用的速度。
虽然Memcached的守护进程是用C写的,但是客户端可以用任何语言来编写,并通过Memcached协议与守护进程进行通信。
因为Spring Boot暂时还没有提供 Memcached相关的支持包,因此需要我们通过集成第三方提供的Memcached客户端来实现。
Spymemcached是官方推出的一个Memcached Java客户端,使用NIO实现,异步、单线程,在性能上表现出色,
广泛应用于Java + Memcached项目中。
下载安装地址 :
https://www.runoob.com/memcached/window-install-memcached.html
本次下载:
64位系统 1.4.5版本:http://static.runoob.com/download/memcached-1.4.5-amd64.zip
安装:
1、解压下载的安装包到指定目录。
2、在 memcached1.4.5 版本之后,memcached 不能作为服务来运行,需要使用任务计划中来开启一个普通的进程,
在 window 启动时设置 memcached自动执行。
我们使用管理员身份执行以下命令将 memcached 添加来任务计划表中:
schtasks /create /sc onstart /tn memcached /tr "'D:JAVAMemcachedmemcached-amd64memcached.exe' -m 512"
D:JAVAMemcachedmemcached-amd64memcached.exe 是我的解压缩地址
注意:-m 512 意思是设置 memcached 最大的缓存配置为512M。
注意:我们可以通过使用 "D:JAVAMemcachedmemcached-amd64memcached.exe -h" 命令查看更多的参数配置。
3、如果需要删除 memcached 的任务计划可以执行以下命令:
schtasks /delete /tn memcached
4、启动和关闭 memcached 服务:
D:JAVAMemcachedmemcached-amd64memcached.exe -d start (执行后没有成功和错误信息,表示成功)
D:JAVAMemcachedmemcached-amd64memcached.exe -d stop (执行后没有成功和错误信息,表示成功)
命令参考:https://www.cnblogs.com/gyfluck/p/9239370.html
启动以后之后
可以 本地 Telnet 127.0.0.1 11211 看是否能访问
整合环境 :
jdk:1.8
版本: memcached-1.4.5-amd64
创建一个springboot项目
依赖的jar:
<dependency> <groupId>net.spy</groupId> <artifactId>spymemcached</artifactId> <version>2.12.3</version> </dependency>
< 完整pom在最后 >
application.properties:
memcache.ip=127.0.0.1
memcache.port=11211
先来个main方法 测试一下:
package com.infinitepossibilities.Test; import net.spy.memcached.MemcachedClient; import java.net.InetSocketAddress; import java.util.concurrent.Future; public class Demo { public static void main(String[] args) throws Exception { test(); } public static void test() throws Exception { MemcachedClient memcachedClient = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211)); //设置缓存 过期时间单位为秒, 0表示永远不过期 Future future = memcachedClient.set("yiwang", 5, "tongban"); Object data; System.out.println("************* : "+future.get());//返回状态 true or false data= memcachedClient.get("yiwang"); System.out.println("第一次取出数据:"+data); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } data = memcachedClient.get("yiwang"); System.out.println("第二次取出数据:"+data); memcachedClient.shutdown(); } }
MemcacheConfig:
package com.infinitepossibilities.config; import net.spy.memcached.MemcachedClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; import java.net.InetSocketAddress; @Configuration public class MemcacheConfig { @Value("${memcache.ip}") private String ip; @Value("${memcache.port}") private int port; @Bean public MemcachedClient getMemcachedClient(){ MemcachedClient memcachedClient = null; try { memcachedClient = new MemcachedClient(new InetSocketAddress(ip,port)); } catch (IOException e) { e.printStackTrace(); } return memcachedClient; } }
MemcacheController:
package com.infinitepossibilities.controller; import net.spy.memcached.CASResponse; import net.spy.memcached.CASValue; import net.spy.memcached.MemcachedClient; import net.spy.memcached.internal.OperationFuture; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MemcacheController { @Autowired private MemcachedClient memcachedClient; @RequestMapping("/getAndset") public void getAndset() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); //shanghai try { //让 key 过期 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data); //null } /** * Memcached add 命令用于将 value(数据值) 存储在指定的 key(键) 中。 * * 如果 add 的 key 已经存在,则不会更新数据(过期的 key 会更新),之前的值将仍然保持相同,并且您将获得响应 NOT_STORED。 */ @RequestMapping("/add") public void add() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); memcachedClient.add("zhongguo",5, "2"); // 进行 Add操作 data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data);// 之前的值未过期,新值不生效 try { //让 key 过期 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } memcachedClient.add("zhongguo",5, "2"); // 再进行 Add操作 System.out.println("第三次取出数据:"+memcachedClient.get("zhongguo")); //取出值为2 } /** * replace 命令用于替换已存在的 key(键) 的 value(数据值)。 * * 如果 key 不存在,则替换失败,并且您将获得响应 NOT_STORED。 */ @RequestMapping("/replace") public void replace() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); memcachedClient.replace("zhongguo",5, "2"); // 进行 replace 操作 data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data);// 值更新为 2 try { //让 key 过期 Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } memcachedClient.replace("zhongguo",5, "shanghai"); // 再进行 replace 操作 System.out.println("第三次取出数据:"+memcachedClient.get("zhongguo")); //key 为空, 取出结果为 null } /** * append 命令用于向已存在 key(键) 的 value(数据值) 后面追加数据 */ @RequestMapping("/append") public void append() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); memcachedClient.append("zhongguo","2"); // 进行 append 操作 data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data);// 值更新为 shanghai2 try { //让 key 过期 Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } memcachedClient.append("zhongguo","shanghai"); // 再进行 append 操作 System.out.println("第三次取出数据:"+memcachedClient.get("zhongguo")); //key 为空, 取出结果为 null } /** * prepend 命令用于向已存在 key(键) 的 value(数据值) 后面追加数据 */ @RequestMapping("/prepend") public void prepend() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); memcachedClient.prepend("zhongguo","2"); // 进行 prepend 操作 data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data);// 值更新为 2shanghai try { //让 key 过期 Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } memcachedClient.prepend("zhongguo","shanghai"); // 再进行 prepend 操作 System.out.println("第三次取出数据:"+memcachedClient.get("zhongguo")); //key 为空, 取出结果为 null } /** * CAS(Check-And-Set 或 Compare-And-Swap) 命令用于执行一个"检查并设置"的操作 * * 它仅在当前客户端最后一次取值后,该key 对应的值没有被其他客户端修改的情况下, 才能够将值写入。 * * 检查是通过cas_token参数进行的, 这个参数是Memcach指定给已经存在的元素的一个唯一的64位值。 */ @RequestMapping("/cas") public void cas() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data= memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:"+data); //通过 gets 获取 CAS token (令牌) CASValue casValue = memcachedClient.gets("zhongguo"); System.out.println("CAS token -- : " + casValue); //{CasValue 20/shanghai} //使用cas方法来更新数据 CASResponse casResponse = memcachedClient.cas("zhongguo",casValue.getCas(),5,"2"); System.out.println("CAS 响应信息 :"+casResponse);// OK data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:"+data); // 2 try { //让 key 过期 Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } //通过 gets 获取 CAS token (令牌) CASValue casValue2 = memcachedClient.gets("zhongguo"); System.out.println("CAS token -- : " + casValue2); //null //使用cas方法来更新数据 CASResponse casResponse2 = memcachedClient.cas("zhongguo",casValue.getCas(),5,"2"); System.out.println("CAS 响应信息 :"+casResponse2);// NOT_FOUND data = memcachedClient.get("zhongguo"); System.out.println("第三次取出数据:"+data); // null } /** * delete 命令用于删除已存在的 key(键)。 */ @RequestMapping("/delete") public void delete() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "shanghai"); System.out.println(flag); Object data; data = memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:" + data); //shanghai OperationFuture<Boolean> zhongguo = memcachedClient.delete("zhongguo"); System.out.println(zhongguo.getStatus()); //{OperationStatus success=true: DELETED} data = memcachedClient.get("zhongguo"); System.out.println("第二次取出数据:" + data); //null //没有 key 的情况下 OperationFuture<Boolean> zhongguo2 = memcachedClient.delete("zhongguo"); System.out.println(zhongguo2.getStatus()); //{OperationStatus success=false: NOT_FOUND} } /** * Memcached incr 与 decr 命令用于对已存在的 key(键) 的数字值进行自增或自减操作。 * * incr 与 decr 命令操作的数据必须是十进制的32位无符号整数。 * * 如果 key 不存在返回 NOT_FOUND,如果键的值不为数字,则返回 CLIENT_ERROR,其他错误返回 ERROR。 */ @RequestMapping("/incrOrDecr") public void incrOrDecr() { //设置缓存 过期时间单位为秒, 0表示永远不过期 OperationFuture<Boolean> flag = memcachedClient.set("zhongguo", 5, "1000"); System.out.println(flag); Object data; data = memcachedClient.get("zhongguo"); System.out.println("第一次取出数据:" + data); // 1000 long incr = memcachedClient.incr("zhongguo", 100); System.out.println("取出 incr 之后的数据:" + memcachedClient.get("zhongguo")); // 1100 long decr = memcachedClient.decr("zhongguo", 100); System.out.println("取出 decr 之后的数据:" + memcachedClient.get("zhongguo")); // 1000 memcachedClient.append("zhongguo","shanghai"); System.out.println("取出 append 之后的数据:" + memcachedClient.get("zhongguo")); // 1000shanghai //ERROR net.spy.memcached.protocol.ascii.MutatorOperationImpl: Error: CLIENT_ERROR cannot increment or decrement non-numeric value long incr2 = memcachedClient.incr("zhongguo", 100); System.out.println("取出 incr 之后的数据:" + memcachedClient.get("zhongguo")); // 1000shanghai //ERROR net.spy.memcached.protocol.ascii.MutatorOperationImpl: Error: CLIENT_ERROR cannot increment or decrement non-numeric value long decr2 = memcachedClient.decr("zhongguo", 100); System.out.println("取出 decr 之后的数据:" + memcachedClient.get("zhongguo"));// 1000shanghai try { //让 key 过期 Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } //key 过期后 未报错 但返回 的都是 -1 long incr3 = memcachedClient.incr("zhongguo", 100); System.out.println(incr3); // -1 System.out.println("取出 incr 之后的数据:" + memcachedClient.get("zhongguo")); // null long decr3 = memcachedClient.decr("zhongguo", 100); System.out.println(decr3); // -1 System.out.println("取出 decr 之后的数据:" + memcachedClient.get("zhongguo"));// null } }
pom:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.infinitePossibilities</groupId> <artifactId>memcached</artifactId> <version>0.0.1-SNAPSHOT</version> <name>memcached</name> <description>memcached</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>net.spy</groupId> <artifactId>spymemcached</artifactId> <version>2.12.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Githup: https://github.com/lifan12589/infinite-possibilities/tree/master/ac-memcached