一、Redis简介

Redis是开源的内存数据结构存储系统,可用作数据库、缓存和消息队列。

特点:

  • 高性能:基于内存操作
  • 丰富数据类型:String、List、Set、Hash、ZSet等
  • 持久化:RDB和AOF
  • 高可用:主从复制、哨兵、集群

二、SpringBoot整合Redis

添加依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置连接

1
2
3
4
5
6
7
8
9
10
11
12
spring:
redis:
host: localhost
port: 6379
password:
database: 0
timeout: 3000
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0

配置RedisTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);

// 使用Jackson序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);

template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);

template.afterPropertiesSet();
return template;
}
}

三、String操作

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Autowired
private RedisTemplate<String, Object> redisTemplate;

// 设置值
redisTemplate.opsForValue().set("key", "value");

// 设置值,带过期时间
redisTemplate.opsForValue().set("key", "value", 1, TimeUnit.HOURS);

// 设置值,如果不存在
redisTemplate.opsForValue().setIfAbsent("key", "value");

// 获取值
Object value = redisTemplate.opsForValue().get("key");

// 删除
redisTemplate.delete("key");

// 检查存在
Boolean exists = redisTemplate.hasKey("key");

// 设置过期时间
redisTemplate.expire("key", 1, TimeUnit.HOURS);

计数器

1
2
3
4
5
6
// 自增
Long increment = redisTemplate.opsForValue().increment("counter");
Long increment = redisTemplate.opsForValue().increment("counter", 10);

// 自减
Long decrement = redisTemplate.opsForValue().decrement("counter");

四、Hash操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 设置hash字段
redisTemplate.opsForHash().put("user:1", "name", "张三");
redisTemplate.opsForHash().put("user:1", "age", "20");

// 设置多个字段
Map<String, Object> map = new HashMap<>();
map.put("name", "李四");
map.put("age", "25");
redisTemplate.opsForHash().putAll("user:2", map);

// 获取字段
Object name = redisTemplate.opsForHash().get("user:1", "name");

// 获取所有字段
Map<Object, Object> user = redisTemplate.opsForHash().entries("user:1");

// 删除字段
redisTemplate.opsForHash().delete("user:1", "name");

// 字段自增
redisTemplate.opsForHash().increment("user:1", "age", 1);

// 检查字段存在
Boolean exists = redisTemplate.opsForHash().hasKey("user:1", "name");

五、List操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 左侧插入
redisTemplate.opsForList().leftPush("list", "value1");
redisTemplate.opsForList().leftPushAll("list", "value2", "value3");

// 右侧插入
redisTemplate.opsForList().rightPush("list", "value4");

// 获取范围
List<Object> list = redisTemplate.opsForList().range("list", 0, -1);

// 左侧弹出
Object value = redisTemplate.opsForList().leftPop("list");

// 右侧弹出
Object value = redisTemplate.opsForList().rightPop("list");

// 获取长度
Long size = redisTemplate.opsForList().size("list");

// 通过索引获取
Object value = redisTemplate.opsForList().index("list", 0);

// 通过索引设置
redisTemplate.opsForList().set("list", 0, "newValue");

六、Set操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 添加元素
redisTemplate.opsForSet().add("set", "value1", "value2");

// 获取所有元素
Set<Object> set = redisTemplate.opsForSet().members("set");

// 删除元素
redisTemplate.opsForSet().remove("set", "value1");

// 检查元素存在
Boolean exists = redisTemplate.opsForSet().isMember("set", "value1");

// 获取大小
Long size = redisTemplate.opsForSet().size("set");

// 随机获取
Object value = redisTemplate.opsForSet().randomMember("set");

// 交集
Set<Object> intersect = redisTemplate.opsForSet().intersect("set1", "set2");

// 并集
Set<Object> union = redisTemplate.opsForSet().union("set1", "set2");

七、ZSet操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 添加元素
redisTemplate.opsForZSet().add("zset", "value1", 100);
redisTemplate.opsForZSet().add("zset", "value2", 200);

// 获取排名范围
Set<Object> set = redisTemplate.opsForZSet().range("zset", 0, -1);

// 获取分数范围
Set<Object> set = redisTemplate.opsForZSet().rangeByScore("zset", 0, 200);

// 获取排名
Long rank = redisTemplate.opsForZSet().rank("zset", "value1");

// 获取分数
Double score = redisTemplate.opsForZSet().score("zset", "value1");

// 增加分数
redisTemplate.opsForZSet().incrementScore("zset", "value1", 10);

// 删除元素
redisTemplate.opsForZSet().remove("zset", "value1");

// 删除排名范围
redisTemplate.opsForZSet().removeRange("zset", 0, 10);

八、缓存注解

启用缓存

1
2
3
4
5
6
7
@EnableCaching
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@Cacheable

查询时使用缓存

1
2
3
4
@Cacheable(value = "user", key = "#id")
public User getUserById(Long id) {
return userMapper.selectById(id);
}

@CachePut

更新缓存

1
2
3
4
5
@CachePut(value = "user", key = "#user.id")
public User updateUser(User user) {
userMapper.updateById(user);
return user;
}

@CacheEvict

删除缓存

1
2
3
4
@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {
userMapper.deleteById(id);
}

九、分布式锁

使用SETNX实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.opsForValue()
.setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
return result != null && result;
}

public void unlock(String key, String value) {
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
value
);
}

使用Redisson

1
2
3
4
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
@Autowired
private RedissonClient redissonClient;

public void doSomething() {
RLock lock = redissonClient.getLock("myLock");
try {
lock.lock();
// 业务逻辑
} finally {
lock.unlock();
}
}

十、最佳实践

Key命名规范

1
2
3
// 推荐格式:业务:模块:id
String key = "user:info:1001";
String key = "order:detail:2001";

序列化选择

  • Key:StringRedisSerializer
  • Value:Jackson2JsonRedisSerializer

过期时间

1
2
// 设置合理过期时间
redisTemplate.opsForValue().set("key", "value", 1, TimeUnit.HOURS);

批量操作

1
2
3
4
5
6
7
8
9
// 使用Pipeline减少网络开销
redisTemplate.executePipelined(new SessionCallback<Object>() {
@Override
public Object execute(RedisOperations operations) {
operations.opsForValue().set("key1", "value1");
operations.opsForValue().set("key2", "value2");
return null;
}
});

十一、总结

SpringBoot整合Redis要点:

  • 配置RedisTemplate和序列化器
  • 熟练使用各数据类型操作
  • 合理使用缓存注解
  • 分布式锁保证并发安全
  • 遵循最佳实践规范