# 键过期竞态条件：TTL 已更新但键已过期

- **ID:** `redis/key-expiry-race-condition`
- **领域:** redis
- **类别:** runtime_error
- **错误码:** `ERM`
- **验证级别:** ai_generated
- **修复率:** 85%

## 根因

多个客户端同时更新 TTL 和键值时发生竞态条件，导致键在 TTL 更新生效前已过期。

## 版本兼容性

| 版本 | 状态 | 引入 | 弃用 |
|------|------|------|------|
| 6.0 | active | — | — |
| 7.0 | active | — | — |
| 7.2 | active | — | — |

## 解决方案

1. ```
   使用 EVAL 执行脚本：'local val = redis.call("GET", KEYS[1]); if val then redis.call("SET", KEYS[1], ARGV[1]); redis.call("EXPIRE", KEYS[1], ARGV[2]); return 1 else return 0 end'。
   ```
2. ```
   在 GET 前使用 WATCH 监视键，然后使用 MULTI/EXEC 更新 TTL。如果 WATCH 触发，则重试。
   ```

## 无效尝试

- **** — SET with EX still has a race if key is deleted by another client before EXPIRE. (50% 失败率)
- **** — Redis transactions are not atomic for conditional operations; EXPIRE may still fail if key expires during transaction. (60% 失败率)
- **** — Race condition persists; repeated failures under high concurrency. (75% 失败率)
