Memcached 过期时间的核心概念
在深入 Java 客户端之前,必须先理解 Memcached 服务端是如何处理过期时间的。

- 单位:过期时间的单位是 秒。
- 设置方式:在
set,add,replace等STORE命令中,通过一个额外的参数来指定。 - 过期时间范围:
- 大于 0 的整数:表示在多少秒后过期。
3600表示 1 小时后过期。 - 0:表示 立即过期,这相当于删除该缓存项,这在某些场景下比
delete命令更高效,因为它避免了网络往返(客户端发送删除命令,服务端确认)。 - *小于 `60602430
(即 30 天) 的 Unix 时间戳**:表示在指定的 UTC 时间点过期。1672531200` 代表 2025-01-01 00:00:00 UTC。 - *大于等于 `60602430` 的整数Memcached 会将其解释为 Unix 时间戳** 而不是秒数,这是为了避免在设置远期过期时间(如 30 天后)时误用。
- 大于 0 的整数:表示在多少秒后过期。
- 惰性删除:Memcached 不会在后台主动扫描所有键来检查是否过期,它只在客户端请求某个键时,才会检查该键是否已过期,如果已过期,它不会返回数据,并在内存中将其释放。
- LRU 策略:当 Memcached 内存不足时,它会使用 最近最少使用 策略来淘汰内存中的数据,即使一个数据还没到过期时间,也可能因为很久没有被访问而被 LRU 算法淘汰。
Java 客户端设置过期时间
在 Java 中,我们通常使用第三方客户端库来与 Memcached 交互,最流行和功能最强大的库是 XMemcached,我们以它为例来讲解。
1 Maven 依赖
在你的 pom.xml 文件中添加 XMemcached 的依赖:
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.7</version> <!-- 建议使用较新版本 -->
</dependency>
2 核心方法:set 和 add
XMemcached 客户端提供了 set 和 add 方法来存储数据,它们都支持过期时间参数。
-
set(String key, int expiration, Object value)
(图片来源网络,侵删)- 功能:将一个值与一个键关联,如果键已存在,则覆盖其旧值。
- 参数:
key: 缓存键。expiration: 过期时间(秒),这是设置过期时间的关键参数。value: 要缓存的对象。
-
add(String key, int expiration, Object value)- 功能:将一个值与一个键关联。仅当键不存在时才会设置成功,如果键已存在,操作会失败。
- 参数:与
set方法相同。
3 代码示例
下面是一个完整的示例,演示如何使用 XMemcached 设置不同类型的过期时间。
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClient;
import net.rubyeye.xmemcached.exception.MemcachedException;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class MemcachedExpirationExample {
public static void main(String[] args) {
// 1. 创建 Memcached 客户端
// 参数是 Memcached 服务器地址和端口
try (MemcachedClient memcachedClient = new XMemcachedClient("localhost", 11211)) {
System.out.println("--- 设置 10 秒后过期的键 ---");
// 设置一个键 "user:1001",10 秒后过期
memcachedClient.set("user:1001", 10, "Alice");
System.out.println("设置 'user:1001' 成功,值为 'Alice',10秒后过期。");
// 立即获取,应该能拿到
Object value = memcachedClient.get("user:1001");
System.out.println("立即获取 'user:1001': " + value);
// 等待 11 秒,让缓存过期
Thread.sleep(11000);
// 再次获取,应该为 null
value = memcachedClient.get("user:1001");
System.out.println("11秒后获取 'user:1001': " + value); // 预期输出: null
System.out.println("\n--- 设置 0 秒后过期的键 (立即删除) ---");
// 先设置一个值
memcachedClient.set("temp_key", 3600, "This is a temporary value.");
System.out.println("设置 'temp_key' 成功,值为 'This is a temporary value.'。");
// 使用 0 作为过期时间,立即删除
memcachedClient.set("temp_key", 0, null); // 值设为 null,过期时间设为 0
// 或者更直接的方式是使用 delete 命令: memcachedClient.delete("temp_key");
System.out.println("设置 'temp_key' 过期时间为 0,相当于删除。");
// 获取,应该为 null
value = memcachedClient.get("temp_key");
System.out.println("获取 'temp_key': " + value); // 预期输出: null
System.out.println("\n--- 使用 add 方法,键已存在则设置失败 ---");
// 先设置一个键
memcachedClient.set("another_key", 60, "First Value");
System.out.println("首次设置 'another_key' 成功。");
// 尝试用 add 方法再次设置同一个键,这会失败
boolean result = memcachedClient.add("another_key", 120, "Second Value");
System.out.println("尝试用 add 方法再次设置 'another_key': " + result); // 预期输出: false
// 获取值,仍然是第一次设置的值
value = memcachedClient.get("another_key");
System.out.println("获取 'another_key' 的值: " + value); // 预期输出: First Value
} catch (IOException | InterruptedException | TimeoutException | MemcachedException e) {
e.printStackTrace();
}
}
}
其他相关操作
除了在存储时设置过期时间,还有一些其他相关操作。
1 replace 方法
replace 方法用于更新一个已存在的键的值,如果键不存在,操作会失败,它同样支持在更新时修改过期时间。

// 假设 "user:1001" 已存在且过期时间为 10 秒
// 将其值更新为 "Bob",并重置过期时间为 60 秒
boolean replaced = memcachedClient.replace("user:1001", 60, "Bob");
System.out.println("replace 操作是否成功: " + replaced); // 如果键存在,则为 true
2 touch 方法
这是一个非常有用的方法,它允许你在不改变键值的情况下,更新其过期时间。
- 用途:当你发现一个即将过期的键仍然被频繁访问时,可以使用
touch来“延长”它的生命,而无需从数据库重新加载整个值。 - 参数:键和新过期时间(秒)。
// 假设 "user:1001" 存在且即将过期
// 将其过期时间延长到 5 分钟 (300 秒) 后
boolean touched = memcachedClient.touch("user:1001", 300);
System.out.println("touch 操作是否成功: " + touched); // 预期输出: true
3 delete 方法
delete 方法用于立即从缓存中移除一个键,它没有过期时间参数,因为它的作用是立即删除。
// 立即删除 "user:1001"
memcachedClient.delete("user:1001");
最佳实践和注意事项
- 选择合适的过期时间:
- 对于热点数据(如首页信息、用户会话),可以设置较长的过期时间(如 30 分钟到几小时)。
- 对于可能频繁变化的数据(如商品库存、用户状态),应设置较短的过期时间(如几秒或几分钟),或者采用缓存穿透/雪崩
