Memcached - 获取 CAS 数据
Memcached - 使用 CAS 进行原子更新
Section titled “Memcached - 使用 CAS 进行原子更新”CAS(Check-And-Set,检查并设置)是 Memcached 的一个强大功能,允许您执行原子性的读-修改-写操作。它能防止多个客户端同时尝试更新同一个键,从而可能覆盖彼此更改的竞态条件。gets 命令是 CAS 操作的第一步;它检索一个项及其唯一的 64 位 ‘CAS 令牌’。
语法:gets 命令
Section titled “语法:gets 命令”语法与 get 命令相同,但服务器的响应中包含一个额外的值:CAS 令牌。
gets key# 首先,设置一个要操作的值set user:profile 0 900 20{"name":"Alice","visits":10}STORED
# 现在,使用 gets 获取值及其 CAS 令牌gets user:profileVALUE user:profile 0 20 52{"name":"Alice","visits":10}END在 VALUE 行中,数字 52 是此项当前状态的唯一 CAS 令牌。必须将此令牌与 cas 命令一起发送回去,才能成功更新该项。如果另一个客户端首先修改了该项,CAS 令牌将发生变化,您的更新将失败。
在 Java 中实现 CAS 工作流
Section titled “在 Java 中实现 CAS 工作流”完整的 Check-And-Set 工作流包括三个步骤:1) 使用 gets 检索值及其令牌。2) 在应用程序代码中修改值。3) 使用 cas 将新值写回,并提供原始令牌。只有当服务器上的令牌与您提供的令牌仍然匹配时,更新才会成功。
Java 示例
Section titled “Java 示例”import net.spy.memcached.CASValue;import net.spy.memcached.CASResponse;import net.spy.memcached.MemcachedClient;import java.net.InetSocketAddress;
public class CasExample { public static void main(String[] args) { MemcachedClient mcc = null; try { mcc = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211)); System.out.println("Connection to server successful.");
// 1. 初始化我们要原子修改的值 String key = "user:settings"; mcc.set(key, 900, "theme:dark").get(); // .get() 等待操作完成 System.out.println("Initial value set to: 'theme:dark'");
// --- CAS 操作开始 ---
// 2. 获取值及其 CAS 令牌 CASValue<Object> casValue = mcc.gets(key); if (casValue == null) { System.err.println("缓存未命中。找不到键:" + key); return; // 如果键不存在则退出 }
System.out.println("Retrieved value: '" + casValue.getValue() + "' with CAS token: " + casValue.getCas());
// 3. 在应用程序逻辑中修改值 String newValue = "theme:light";
// 4. 尝试使用 cas() 命令更新 // cas 方法接受:键、原始 CAS 令牌、过期时间以及新值。 CASResponse response = mcc.cas(key, casValue.getCas(), 900, newValue);
System.out.println("Attempting CAS update with new value '" + newValue + "'..."); System.out.println("CAS Operation Result: " + response);
if (response == CASResponse.OK) { System.out.println("Update successful!"); } else { System.out.println("Update failed. The value was likely modified by another client."); }
// 为了证明,我们获取最终值 System.out.println("Final value in cache: " + mcc.get(key));
} catch (Exception e) { System.err.println("An error occurred: " + e.getMessage()); } finally { if (mcc != null) { mcc.shutdown(); } } }}Connection to server successful.Initial value set to: 'theme:dark'Retrieved value: 'theme:dark' with CAS token: 53Attempting CAS update with new value 'theme:light'...CAS Operation Result: OKUpdate successful!Final value in cache: theme:light处理 CAS 失败
Section titled “处理 CAS 失败”当 cas 操作返回 EXISTS(表示数据被另一个进程更改)或 NOT_FOUND(表示数据已被删除)时,您的应用程序不应放弃。标准做法是实现一个重试循环。此循环将重新运行整个 gets -> 修改 -> cas 周期,直到成功或达到最大重试次数以防止无限循环。