第 3 课:Java 客户端操作 Redis
学习目标
完成本课后,你将掌握:
- Java 操作 Redis 的主流方案
- Jedis 的使用方法
- Jedis 连接池配置
- Spring Boot 整合 Redis
- RedisTemplate 的使用
- Redis 序列化问题解决方案
- Redis 工具类封装
- 企业项目中的 Redis 使用规范
Java 操作 Redis 的三种方案
目前 Java 项目中主流的 Redis 客户端有:
| 客户端 | 特点 | 推荐指数 |
|---|---|---|
| Jedis | 简单易用,传统方案 | ⭐⭐⭐ |
| Lettuce | 基于 Netty,支持异步 | ⭐⭐⭐⭐ |
| Spring Data Redis | Spring 官方方案 | ⭐⭐⭐⭐⭐ |
方案对比
| 对比项 | Jedis | Lettuce | Spring Data Redis |
|---|---|---|---|
| 使用难度 | 简单 | 中等 | 简单 |
| 性能 | 较高 | 高 | 高 |
| 线程安全 | 否 | 是 | 是 |
| 是否推荐新项目 | 一般 | 推荐 | 强烈推荐 |
| Spring Boot 整合 | 一般 | 优秀 | 最佳 |
3.1 Jedis 基本使用
什么是 Jedis?
Jedis 是 Redis 官方推荐的 Java 客户端之一。
特点:
- API 简单
- 学习成本低
- 使用方便
- 适合学习 Redis
引入依赖
Maven
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.3</version>
</dependency>
创建连接
import redis.clients.jedis.Jedis;
public class JedisDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost",6379);
System.out.println(jedis.ping());
jedis.close();
}
}
运行结果:
PONG
表示连接成功。
String 操作
Jedis jedis = new Jedis("localhost",6379);
jedis.set("name","zhangsan");
String name = jedis.get("name");
System.out.println(name);
jedis.close();
输出:
zhangsan
Hash 操作
Jedis jedis = new Jedis("localhost",6379);
jedis.hset("user:1001","name","lisi");
jedis.hset("user:1001","age","25");
System.out.println(
jedis.hgetAll("user:1001")
);
jedis.close();
输出:
{name=lisi, age=25}
List 操作
Jedis jedis = new Jedis("localhost",6379);
jedis.lpush("list1","a","b","c");
System.out.println(
jedis.lrange("list1",0,-1)
);
jedis.close();
输出:
[c,b,a]
Jedis 的问题
Jedis 对象:
不是线程安全的
错误示例:
多个线程共享同一个 Jedis
容易出现:
连接异常
数据错误
性能下降
因此:
生产环境必须使用连接池
3.1.1 Jedis 连接池
为什么需要连接池?
如果每次请求:
创建连接
↓
执行命令
↓
关闭连接
会产生大量开销。
连接池可以:
- 复用连接
- 提升性能
- 降低资源消耗
配置连接池
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolUtil {
private static JedisPool jedisPool;
static {
JedisPoolConfig config =
new JedisPoolConfig();
config.setMaxTotal(20);
config.setMaxIdle(5);
config.setMinIdle(2);
config.setTestOnBorrow(true);
jedisPool = new JedisPool(
config,
"localhost",
6379,
2000,
"yourpassword"
);
}
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
获取连接
Jedis jedis = JedisPoolUtil.getJedis();
使用完成关闭
jedis.close();
注意:
这里不是销毁连接
而是归还连接池
3.2 Spring Boot 整合 Redis
企业项目中:
几乎不会直接使用 Jedis
通常使用:
Spring Data Redis
引入依赖
Spring Boot 3.x
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-data-redis
</artifactId>
</dependency>
连接池依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
application.yml 配置
spring:
redis:
host: localhost
port: 6379
password: yourpassword
database: 0
timeout: 2000ms
lettuce:
pool:
max-active: 20
max-idle: 5
min-idle: 2
max-wait: -1ms
配置说明
| 配置项 | 说明 |
|---|---|
| host | Redis地址 |
| port | Redis端口 |
| password | Redis密码 |
| database | 数据库编号 |
| timeout | 超时时间 |
| max-active | 最大连接数 |
| max-idle | 最大空闲连接 |
| min-idle | 最小空闲连接 |
RedisTemplate
Spring Boot 操作 Redis 的核心类:
RedisTemplate
相当于:
MyBatis 的 SqlSession
注入 RedisTemplate
@Resource
private RedisTemplate<String,Object> redisTemplate;
String 操作
保存数据
redisTemplate.opsForValue()
.set("name","zhangsan");
获取数据
Object value =
redisTemplate.opsForValue()
.get("name");
设置过期时间
redisTemplate.opsForValue()
.set(
"code",
"123456",
60,
TimeUnit.SECONDS
);
Hash 操作
设置字段
redisTemplate.opsForHash()
.put(
"user:1001",
"name",
"zhangsan"
);
获取字段
Object name =
redisTemplate.opsForHash()
.get(
"user:1001",
"name"
);
获取全部字段
Map<Object,Object> map =
redisTemplate.opsForHash()
.entries("user:1001");
List 操作
redisTemplate.opsForList()
.leftPush(
"queue",
"message"
);
Object msg =
redisTemplate.opsForList()
.rightPop("queue");
Set 操作
redisTemplate.opsForSet()
.add(
"tags",
"java",
"redis"
);
ZSet 操作
redisTemplate.opsForZSet()
.add(
"rank",
"zhangsan",
100
);
RedisTemplate 序列化问题
默认情况下:
RedisTemplate
使用:
JDK序列化
Redis 中会出现乱码:
\xac\xed\x00\x05...
不方便查看。
自定义 JSON 序列化
RedisConfig
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object>
redisTemplate(
RedisConnectionFactory factory
){
RedisTemplate<String,Object> template =
new RedisTemplate<>();
template.setConnectionFactory(factory);
StringRedisSerializer stringSerializer =
new StringRedisSerializer();
Jackson2JsonRedisSerializer<Object>
jsonSerializer =
new Jackson2JsonRedisSerializer<>(
Object.class
);
template.setKeySerializer(
stringSerializer
);
template.setHashKeySerializer(
stringSerializer
);
template.setValueSerializer(
jsonSerializer
);
template.setHashValueSerializer(
jsonSerializer
);
return template;
}
}
企业项目 Redis 工具类封装
为了避免:
redisTemplate.opsForValue()
redisTemplate.opsForHash()
redisTemplate.opsForList()
到处出现。
一般封装:
RedisUtil
RedisUtil 示例
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String,Object>
redisTemplate;
public void set(
String key,
Object value
){
redisTemplate.opsForValue()
.set(key,value);
}
public Object get(String key){
return redisTemplate.opsForValue()
.get(key);
}
public Boolean delete(String key){
return redisTemplate.delete(key);
}
}
企业项目实战:用户缓存
场景
用户信息查询频繁。
如果每次:
用户
↓
MySQL
数据库压力非常大。
正确方案
用户
↓
Redis
↓
MySQL
查询流程
查询用户
↓
Redis是否存在
↓
是
↓
直接返回
↓
否
↓
查询MySQL
↓
写入Redis
↓
返回数据
代码示例
public User getUser(Long id){
String key = "user:" + id;
User user =
(User) redisUtil.get(key);
if(user != null){
return user;
}
user = userMapper.selectById(id);
if(user != null){
redisUtil.set(
key,
user
);
}
return user;
}
企业项目实战:文章阅读量
Redis 计数器
文章访问:
redisTemplate.opsForValue()
.increment(
"article:view:1001"
);
Redis:
article:view:1001 = 123456
优势:
- 高性能
- 原子操作
- 支持高并发
本课总结
本课学习了:
- Jedis
- Jedis 连接池
- Spring Boot 整合 Redis
- RedisTemplate
- Redis 序列化
- Redis 工具类封装
- 用户缓存案例
- 阅读量统计案例
面试高频题
RedisTemplate 和 StringRedisTemplate 的区别?
| 类型 | Value类型 |
|---|---|
| RedisTemplate | Object |
| StringRedisTemplate | String |
为什么 RedisTemplate 会乱码?
因为默认:
JDK序列化
需要改为:
Jackson JSON序列化
为什么生产环境不用 Jedis?
因为:
Jedis非线程安全
通常使用:
Lettuce
或者:
Spring Data Redis
课后练习
练习 1
创建 Spring Boot 项目。
整合 Redis。
练习 2
实现用户缓存功能:
查Redis
↓
查MySQL
↓
回写Redis
练习 3
实现文章阅读量统计:
increment()
练习 4
封装自己的 RedisUtil 工具类。
支持:
- String
- Hash
- List
- Set
- ZSet
五种数据结构。
下一课预告
第 4 课:Redis 持久化机制
学习内容:
- RDB
- AOF
- 混合持久化
- 数据恢复
- 持久化策略选择
- 企业生产环境配置