缓存的实现
-
Redis(分布式缓存)
-
memcached(分布式)
-
Etcd(云原生架构的一个分布式存储,存储配置,扩容能力)
-
ehcache(单机)
-
本地缓存(Java 内存 Map)
-
Caffeine(Java 内存缓存,高性能)
-
Google Guava
Redis
NoSQL 数据库
key - value 存储系统(区别于 MySQL,他存储的是键值对)
Redis 数据结构
String 字符串类型: name: "yupi"
List 列表:names: ["yupi", "dogyupi", "yupi"]
Set 集合:names: ["yupi", "dogyupi"](值不能重复)
Hash 哈希:nameAge: { "yupi": 1, "dogyupi": 2 }
Zset 集合:names: { yupi - 9, dogyupi - 12 }(适合做排行榜)
Java中Redis的实现
-
Spring Data Redis(推荐)
1)引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.4</version>
</dependency>
2)配置 Redis 地址
spring:
# redis 配置
redis:
port: 6379
host: localhost
database: 0
3)实现redis的配置类
这里是为redis配置一个非原生的序列化器,防止存入redis的键存在乱码前缀。
/**
* redis的配置类,源码中表示redis会默认配置一个java原生的序列化器,这使得k-v结构在存入redis库时,
* k会序列化上一些乱码的前缀,所以我们要自定义一个RedisTemplate
*/
@Configuration
public class RedisTemplateConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string());//return StringRedisSerializer.UTF_8配置一个string的序列化器
return redisTemplate;
}
}
4)操作redis
@SpringBootTest
public class RedisTest {
@Resource
private RedisTemplate redisTemplate;
@Test
void test() {
ValueOperations valueOperations = redisTemplate.opsForValue();
// 增
valueOperations.set("yupiString", "dog");
valueOperations.set("yupiInt", 1);
valueOperations.set("yupiDouble", 2.0);
User user = new User();
user.setId(1L);
user.setUsername("yupi");
valueOperations.set("yupiUser", user);
// 查
Object yupi = valueOperations.get("yupiString");
Assertions.assertTrue("dog".equals((String) yupi));
yupi = valueOperations.get("yupiInt");
Assertions.assertTrue(1 == (Integer) yupi);
yupi = valueOperations.get("yupiDouble");
Assertions.assertTrue(2.0 == (Double) yupi);
System.out.println(valueOperations.get("yupiUser"));
valueOperations.set("yupiString", "dog");
redisTemplate.delete("yupiString");
}
}
5)实践
@GetMapping("/recommend")
public BaseResponse<Page<User>> usersRecommend(long page, long pageSize, HttpServletRequest request){
User loginUser = userService.getLoginUser(request);
String redisKey = String.format("zj:user:recommend:%s", loginUser.getId());
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();//opsForValue存string
//如果有缓存,直接读缓存
Page<User> userListPage = (Page<User>) valueOperations.get(redisKey);
if(userListPage != null) {
return ResultUtils.success(userListPage);
}
//无缓存,查数据库,存入缓存
Page<User> userPage = new Page<>(page, pageSize);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
userService.page(userPage, queryWrapper);
List<User> userList = userPage.getRecords();
userPage.setRecords(userList.stream().map((user) -> {return userService.getSafetyUser(user);}).collect(Collectors.toList()));
try {
//指定键、值、缓存过期时间和时间单位
valueOperations.set(redisKey, userPage, 10000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.error("redis set key error", e);
}
return ResultUtils.success(userPage);
}
- Jedis
独立于 Spring 操作 Redis 的 Java 客户端
要配合 Jedis Pool 使用
- Lettuce
高阶 的操作 Redis 的 Java 客户端
异步、连接池
- Redisson
分布式操作 Redis 的 Java 客户端,让你像在使用本地的集合一样操作 Redis(分布式 Redis 数据网格)
- JetCache
对比
-
如果你用的是 Spring,并且没有过多的定制化要求,可以用 Spring Data Redis,最方便
-
如果你用的不是 SPring,并且追求简单,并且没有过高的性能要求,可以用 Jedis + Jedis Pool
-
如果你的项目不是 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
-
如果你的项目是分布式的,需要用到一些分布式的特性(比如分布式锁、分布式集合),推荐用 redisson