1. 初识Jedis
Jedis的官网地址:https://github.com/redis/jedis
1.1 快速入门
使用步骤:
注意:如果是云服务器用户使用redis需要先配置防火墙!
-
引入maven依赖
<dependencies> <!-- 引入Jedis依赖 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>5.0.0</version> </dependency> <!-- 引入单元测试 --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.1</version> <scope>test</scope> </dependency> </dependencies>
-
建立连接
@BeforeEach void setUp() { jedis = new Jedis("114.55.236.21:22", 6379); jedis.auth("123456"); jedis.select(0); }
-
测试String类的方法
@Test void testString() { // 1. 尝试set方法 jedis.set("name", "wjj"); // 2. 尝试get方法 String name = jedis.get("name"); System.out.println(name); }
-
释放连接
@AfterEach void tearDown() { if (jedis != null) { jedis.close(); } }
运行结果:
2. 使用Jedis连接池
由于Jedis是线程不安全的,并且频繁创建销毁线程具有很大开销,因此我推荐使用连接池的方式使用Jedis
使用步骤:
-
使用连接池创建连接工厂类
/** * 基于连接池实现连接工厂类 */ public class JedisConnectionFactory { private static final JedisPool jedisPool; static { // 1. 创建连接池配置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(8); // 最大连接数 config.setMaxIdle(8); // 最大空闲连接数 config.setMinIdle(0); // 最小空闲连接数 config.setMaxWaitMillis(200); // 最长等待时间 // 2. 创建JedisPool连接池 jedisPool = new JedisPool(config, "114.55.236.21", 6379, 1000, "123456"); } public static Jedis getConnection() { return jedisPool.getResource(); } }
-
编写测试类测试Hash类型方法
public class TestJedisPool { private Jedis jedis; @BeforeEach void setUp() { jedis = JedisConnectionFactory.getConnection(); } @Test void testHash() { // 1. 使用hset方法 jedis.hset("user:1", "name", "rice"); jedis.hset("user:1", "age", "22"); // 2. 使用hgetAll方法 Map<String, String> map = jedis.hgetAll("user:1"); System.out.println(map); } @AfterEach void tearDown() { if (jedis != null) { jedis.close(); } } }
运行结果:
2. 使用SpringBoot整合Redis
现在基于SpringBoot整合Redis已经成为企业的标配,其中SpringDataRedis
就是专门用来操作Redis的集成模块,其具有以下特点:
- 提供了对不同客户端的整合,比如Jedis和Lettuce
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis的哨兵和集群
- 支持Lettuce的响应式编程
- 支持基于JDK、JSON、String等对象的序列化和反序列化
- 支持基于Redis的JDKCollection实现
2.1 SpringDataRedis快速入门
使用步骤:
-
引入maven依赖
<!-- redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 连接池依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency>
-
在
application.yml
中配置相关参数# 配置redis spring: data: redis: host: 114.55.236.21 port: 6379 password: 123456 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: 200
由于Spring官方默认使用lettuce作为客户端,因此如果想要使用Jedis的配置,还需要引入Jedis的maven依赖
-
在测试类中自动装配RedisTemplate对象
@Autowired private RedisTemplate redisTemplate;
-
创建测试类测试redisTemplate的使用
@SpringBootTest class SpringDataRedisDemoApplicationTests { @Resource public RedisTemplate redisTemplate; @Test public void testString() { System.out.println(redisTemplate); // 1. 存入String类型数据 redisTemplate.opsForValue().set("id", "1"); // 2. 取出String类型数据 Object id = redisTemplate.opsForValue().get("id"); System.out.println(id); } }
运行结果:
但是我们发现其中插入了一个\xac\xed\x00\x05t\x00\x02id
这样不知名的key,但是貌似是我们在代码中插入的key值id,但是怎么会以这样的方式呈现呢?
我们追溯源码可以发现RedisTemplate中使用默认的序列化器就是JDK序列化器,其接收Object类型参数并转换成字节数组存入Redis中,但是我们发现具有以下问题:
- 可读性差
- 内存占用较大
因此我们更加建议使用String类型序列化器作为keySerializer,而使用JSON序列化器作为valueSerializer
2.2 使用自定义序列化器
使用步骤:
-
创建Redis配置类
RedisConfig.java
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); // 设置连接工厂 redisTemplate.setConnectionFactory(connectionFactory); // 设置序列化工具 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); // key和hashKey使用StringSerializer redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string()); // value和hashValue使用GenericJackson2JsonRedisSerializer redisTemplate.setValueSerializer(jsonRedisSerializer); redisTemplate.setHashValueSerializer(jsonRedisSerializer); return redisTemplate; } }
-
编写测试类
TestJsonSerializer.java
@SpringBootTest public class TestJsonSerializer { @Autowired private RedisTemplate<String, Object> redisTemplate; @Test public void testJsonSerializer() { // 存放id redisTemplate.opsForValue().set("id", "2"); // 取出id Object id = redisTemplate.opsForValue().get("id"); System.out.println(id); } }
如果出现如下异常(莫慌,这是正常的!):
只要引入如下依赖即可:
<!-- 引入jackson-databind依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.14.1</version>
</dependency>
运行结果:
此时可以发现id正常显示!
但是如果我们尝试将value设置为Java的对象,就会出现一定问题:
使用步骤:
-
创建pojo包下的实体类
User.java
@Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String name; private Integer age; }
-
在测试类中新增测试方法
@Test public void testJsonObjectSerializer() { // 创建User类对象 User user = new User(1, "zhangsan", 22); // 存放User对象 redisTemplate.opsForValue().set("user:1", user); // 取出User对象 User getUser = (User) redisTemplate.opsForValue().get("user:1"); System.out.println(getUser); }
上述方法尝试将一个User类对象作为value,由于之前我们自定义了value的序列化器为JSON序列化器,因此其内部会自动进行序列化和反序列化
运行结果:
我们需要重点关注其中的@class
的字段内容,不难发现,RedisTemplate自动进行序列化和反序列化的依据就是利用Java的反射机制,因此需要保存类信息,但是这也引入了一个严重的问题:
- 如果有上千万的数据量,每条信息都需要保存对应的类信息,会极大浪费内存空间!
因此我们还是建议使用手动序列化的方式进行存取!
2.3 手动序列化
使用步骤:
-
引入JSON工具依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.35</version> </dependency>
-
编写测试类手动序列化
@Test public void testMyJSON() { // 1. 创建User对象 User user = new User(2, "lisi", 22); // 2. 手动序列化为JSON格式数据 String jsonString = JSONObject.toJSONString(user); redisTemplate.opsForValue().set("user:2", jsonString); // 3. 取出数据并手动序列化为User对象 String userJSONString = (String) redisTemplate.opsForValue().get("user:2"); User toUser = JSONObject.parseObject(userJSONString, User.class); System.out.println(toUser); }
运行结果:
此时我们就实现了手动序列化的方式存储Java对象,一切大功告成!