# 四、Redis 客户端
# 1. Java 操作 Redis
Redis 的 Java 客户端也有很多:https://redis.io/clients#java,其中比较受欢迎的是 Jedis
和 Lettuce
。
- Jedis 在实现上是直接连接的 redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个 Jedis 实例增加物理连接,官方推荐。
- Lettuce 的连接是基于 Netty 的, 连接实例(StatefulRedisConnection)可以在多个线程间并发访问,因为 StatefulRedisConnection 是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计, 一个连接实例不够的情况也可以按需增加连接实例。
- 在 SpringBoot Data Redis 1.x 之前默认使用的是 Jedis,但目前最新版的修改成了 Lettuce。
- 之前公司使用 Jedis 居多,Lettuce 近两年在逐步上升,总的来讲 Jedis 的性能会优于 Lettuce(因为它是直接操作Redis)。
# 1.1 环境准备
创建 Maven 项目
引入依赖坐标
<!-- jedis 客户端 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.6.0</version> </dependency> <!-- junit 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency>
# 1.2 代码演示
package com.hedon;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
Jedis jedis = null;
// 初始化
@Before
public void testInit(){
// 初始化 Jedis 客户端,声明主机号和端口
jedis = new Jedis("121.4.146.25", 6379);
// 身份认证
jedis.auth("123456");
// 心跳机制,检测是否连接成功
String pong = jedis.ping();
System.out.println("pong = " + pong);
}
// 操作 Redis
@Test
public void test() {
if (jedis == null) {
return;
}
// 选择数据库
String select = jedis.select(2);
System.out.println("select = " + select);
// 插入数据
String result = jedis.set("username", "zhangsan");
System.out.println("result = " + result);
// 获取数据
result = jedis.get("username");
System.out.println("result = " + result);
}
// 释放资源
@After
public void testClose() {
if (jedis != null) {
// 释放资源
jedis.close();
}
}
}
输出:
pong = PONG
select = OK
result = OK
result = zhangsan
# 1.3 Jedis 连接池优化
封装 JedisPool 工具类
package com.hedon; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * Redis 连接池 */ public class JedisPoolConnectRedis { private static JedisPool jedisPool; // 创建连接池配置对象 static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 设置最大连接数,默认值是 8 jedisPoolConfig.setMaxTotal(5); // 设置最大空闲数量,默认是 8 jedisPoolConfig.setMaxIdle(5); // 设置最少空闲数,默认是 0 jedisPoolConfig.setMinIdle(0); // 设置等待时间 ms jedisPoolConfig.setMaxWaitMillis(100); // 初始化 JedisPool jedisPool = new JedisPool(jedisPoolConfig, "121.4.146.25", 6379, 100, "123456"); } // 静态方法 public static Jedis getJedis(){ return jedisPool.getResource(); } }
测试
package com.hedon; import org.junit.After; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; import java.util.Set; public class JedisPoolTest { Jedis jedis = null; // 初始化 @Before public void testInit(){ // 初始化 Jedis 客户端,声明主机号和端口 jedis = JedisPoolConnectRedis.getJedis(); // 身份认证 jedis.auth("123456"); // 心跳机制,检测是否连接成功 String pong = jedis.ping(); System.out.println("pong = " + pong); } // 操作 Redis @Test public void test() { if (jedis == null) { return; } // 选择数据库 String select = jedis.select(2); System.out.println("select = " + select); // 插入数据 String result = jedis.set("username", "zhangsan"); System.out.println("result = " + result); // 获取数据 result = jedis.get("username"); System.out.println("result = " + result); Set<String> keys = jedis.keys("*"); System.out.println("keys = " + keys); } // 释放资源 @After public void testClose() { if (jedis != null) { // 释放资源 jedis.close(); } } }
# 2. SpringBoot 集成 Redis
# 2.1 环境准备
创建 SpringBoot 项目
添加依赖坐标
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
在
application.yaml
配置文件中配置 Redisspring: redis: host: 121.4.146.25 port: 6379 password: 123456 database: 5 # jedis 连接池版本 jedis: pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: 300 # lettuce 连接池版本 # lettuce: # pool: # max-active: 8 # max-idle: 8 # min-idle: 0 # max-wait: 300
在主启动器内添加 Redis 序列化方法
package com.example.redisspringboot; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @SpringBootApplication public class RedisSpringbootApplication { public static void main(String[] args) { SpringApplication.run(RedisSpringbootApplication.class, args); } /** * redisTemplate 序列化使用的 jdkSerializeable, 存储二进制字节码, 所以自定义序列化类 * * @param redisConnectionFactory * @return */ @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用 Jackson2JsonRedisSerialize 替换默认序列化 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 设置 key 和 value 的序列化规则 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
# 2.2 代码演示
package com.example.redisspringboot;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest(classes = {RedisSpringbootApplication.class})
class RedisSpringbootApplicationTests {
// 注入模板对象
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testRedis(){
System.out.println(redisTemplate.getConnectionFactory().getConnection().ping());
// 获取 Redis 操作对象
ValueOperations valueOperations = redisTemplate.opsForValue();
// 插入数据
valueOperations.set("username", "hedon");
// 获取数据
Object username = valueOperations.get("username");
System.out.println("username = " + username);
}
}
输出:
PONG
username = hedon