跳转到内容

Redis String 类型


String 是 Redis 最基础、使用最广泛的数据类型。它是二进制安全的,可以存储任意内容:普通字符串、整数、浮点数、JSON 字符串,甚至图片的二进制数据(上限 512 MB)。

存储内容示例典型场景
普通字符串"Hello Redis"Token、验证码
整数100计数器、库存
浮点数3.14商品价格
JSON 字符串{"id":1,"name":"Alice"}缓存对象
二进制数据图片字节小文件存储(不推荐)
Terminal window
# 写入
SET key value # 设置 key
SET key value EX 60 # 设置并指定过期时间(秒)
SET key value PX 60000 # 设置并指定过期时间(毫秒)
SET key value NX # key 不存在时才设置(分布式锁常用)
SET key value XX # key 存在时才设置
SET key value EX 60 NX # 组合使用
# 读取
GET key # 获取值,不存在返回 nil
MGET key1 key2 key3 # 批量获取
# 批量写入
MSET key1 val1 key2 val2 # 批量设置
# 先获取再设置
GETSET key newValue # 返回旧值并更新(已废弃,用 SET...GET 替代)
SET key newValue GET # Redis 6.2+ 推荐写法
Terminal window
SET stock 100
INCR stock # 自增 1 → 101(原子操作)
DECR stock # 自减 1 → 100
INCRBY stock 50 # 自增 N → 150
DECRBY stock 30 # 自减 N → 120
INCRBYFLOAT price 0.5 # 浮点自增
Terminal window
APPEND key " World" # 追加内容,返回新长度
STRLEN key # 获取字符串长度(字节数)
GETRANGE key 0 4 # 截取子串(含两端)
SETRANGE key 6 "Redis" # 从指定位置覆写
命令说明时间复杂度
SET key value设置值O(1)
GET key获取值O(1)
MSET / MGET批量读写O(N)
INCR / DECR原子计数O(1)
INCRBY / DECRBY步长计数O(1)
SETNX不存在则设置O(1)
SETEX设置并指定过期O(1)
STRLEN字符串长度O(1)
APPEND追加内容O(1)

Redis 会根据 String 的实际内容自动选择底层编码,以节省内存:

String 底层编码
├── int → 值为整数且范围在 long 以内(如 "100")
├── embstr → 字符串长度 ≤ 44 字节(一次内存分配,只读)
└── raw → 字符串长度 > 44 字节(两次内存分配,可修改)
Terminal window
SET age 18
OBJECT ENCODING age # → int
SET name "Alice"
OBJECT ENCODING name # → embstr
SET bio "This is a very long string that exceeds 44 bytes limit..."
OBJECT ENCODING bio # → raw
spring:
data:
redis:
host: localhost
port: 6379
password: 123456
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Key 使用 String 序列化
template.setKeySerializer(RedisSerializer.string());
// Value 使用 JSON 序列化
template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
template.setHashKeySerializer(RedisSerializer.string());
template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
template.afterPropertiesSet();
return template;
}
}
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 基础读写
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set("token:user:1001", "abc123xyz"); // 永久存储
ops.set("token:user:1001", "abc123xyz", 30, TimeUnit.MINUTES); // 30 分钟过期
String token = ops.get("token:user:1001");
// 批量操作
ops.multiSet(Map.of("k1", "v1", "k2", "v2"));
List<String> values = ops.multiGet(List.of("k1", "k2"));
// 原子计数
ops.set("article:view:1001", "0");
ops.increment("article:view:1001"); // +1
ops.increment("article:view:1001", 10L); // +10
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ObjectMapper objectMapper;
// 存储对象(序列化为 JSON)
public void cacheUser(User user) {
String key = "user:" + user.getId();
String json = objectMapper.writeValueAsString(user);
stringRedisTemplate.opsForValue().set(key, json, 1, TimeUnit.HOURS);
}
// 读取对象(反序列化)
public User getUser(Long userId) throws JsonProcessingException {
String key = "user:" + userId;
String json = stringRedisTemplate.opsForValue().get(key);
if (json == null) return null;
return objectMapper.readValue(json, User.class);
}
// 发送验证码:存入 Redis,5 分钟过期
public void sendVerifyCode(String phone) {
String code = String.valueOf((int)(Math.random() * 900000) + 100000);
String key = "verify:code:" + phone;
stringRedisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
// ... 发送短信
}
// 校验验证码
public boolean verifyCode(String phone, String inputCode) {
String key = "verify:code:" + phone;
String code = stringRedisTemplate.opsForValue().get(key);
if (inputCode.equals(code)) {
stringRedisTemplate.delete(key); // 验证成功后删除,防止重复使用
return true;
}
return false;
}
// 利用 INCR 的原子性生成全局唯一 ID
public long generateId(String bizType) {
String key = "id:seq:" + bizType + ":" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
Long id = stringRedisTemplate.opsForValue().increment(key);
// 设置当天过期,第二天重新从 1 开始
stringRedisTemplate.expire(key, 1, TimeUnit.DAYS);
return id;
}
// 调用:generateId("order") → 20260310000001
// 利用 SET NX 保证同一请求只处理一次
public boolean tryLock(String requestId) {
String key = "idempotent:" + requestId;
// NX:不存在才设置;EX:10 秒过期
Boolean success = stringRedisTemplate.opsForValue()
.setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
return Boolean.TRUE.equals(success);
}

缓存对象时,String(JSON)和 Hash 各有优缺点:

对比项String(JSON)Hash
存储方式整个对象序列化为 JSON每个字段单独存储
读取整个对象一次 GET,简单HGETALL,略复杂
更新单个字段需要先 GET 再 SET 整体HSET 直接更新单字段
内存占用相对较小(JSON 紧凑)字段少时有额外开销
序列化依赖需要 JSON 库无需序列化
推荐场景对象整体读取为主频繁更新单个字段