目录
1 前言
2 Jedis客户端
2.1 jedis快速入门
2.2Jedis连接池
3 SpringDataRedis
3.1快速入门
3.2ReisTemplate配置序列化工具
3.3 StringRedisTemplate
1 前言
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/resources/clients/
因为前三个是官方推荐学习的,而第三个又是基于分布式的,不适合基础学习,所以重点学习前两个。
又因为Java中有前两个命令的整合,叫做Spring Data Redis,但有的企业又是只用到了第一个
所以,我们主要学习两个,Jedis和Spring Data Redis
2 Jedis客户端
2.1 jedis快速入门
Jedis的官网地址: GitHub - redis/jedis: Redis Java client designed for performance and ease of use.,我们先来个快速入门:
温馨提示:一下代码都是在单元测试里实现的哦~
1. 创建Maven工程
2. 导入Jedis客户端h和单元测试依赖:
<dependencies>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
3. 开始实现Jdedis客户端操作
- 建立连接
-
@BeforeEach public void setUp(){ // 1.new Jedis(ip地址,端口) jedis = new Jedis("192.168.110.128",6379); //2.输入密码 auth jedis.auth("123321"); //3.选择库 jedis.select(0); }
- 编写Redis操作(String类型操作)
-
//redis操作 @Test public void testString(){ String result = jedis.set("name", "Jack"); System.out.println(result); String name = jedis.get("name"); System.out.println(name); }
- 关闭资源
-
//关闭资源 @AfterEach public void tearDown(){ //健壮性判断 if (jedis != null){ jedis.close(); } }
最后运行结果:
完整代码如下:
package com.itheima.test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
/**
* @Author 华子
* @Date 2022/11/19 11:15
* @Version 1.0
*/
public class JedisTest {
private Jedis jedis;
//建立连接
@BeforeEach
public void setUp(){
// 1.new Jedis(ip地址,端口)
jedis = new Jedis("192.168.110.128",6379);
//2.输入密码 auth
jedis.auth("123321");
//3.选择库
jedis.select(0);
}
//redis操作
@Test
public void testString(){
String result = jedis.set("name", "Jack");
System.out.println(result);
String name = jedis.get("name");
System.out.println(name);
}
//关闭资源
@AfterEach
public void tearDown(){
//健壮性判断
if (jedis != null){
jedis.close();
}
}
}
2.2Jedis连接池
因为Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。
连接池创建方法如下代码:
package com.itheima.jedis.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisFactory;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @Author 华子
* @Date 2022/11/19 11:41
* @Version 1.0
*/
public class JedisConnectFactory {
private static final JedisPool jedisPool;
static {
//1.配置连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//设置最大连接池数量
jedisPoolConfig.setMaxTotal(8);
//设置最大空闲连接
jedisPoolConfig.setMaxIdle(8);
//设置最小空闲连接
jedisPoolConfig.setMinIdle(0);
//设置最大等待时间(当没有空闲连接时,等待的时间)
jedisPoolConfig.setMaxWaitMillis(1000);
//2.建立连接池(配置参数,ip地址,端口,等待时间,密码)
jedisPool = new JedisPool(jedisPoolConfig,"192.168.110.128",6379,1000,"123321");
}
//3.提供对外调用方法
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
这样连接池就创建成功啦~
而我们Jedis快速入门的时候,建立连接就变为调用这个静态类的getJedis方法了
如图:
整体代码:
package com.itheima.test;
import com.itheima.jedis.util.JedisConnectFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
/**
* @Author 华子
* @Date 2022/11/19 11:15
* @Version 1.0
*/
public class JedisTest {
private Jedis jedis;
//建立连接
@BeforeEach
public void setUp(){
// 1.new Jedis(ip地址,端口)
//jedis = new Jedis("192.168.110.128",6379);
jedis = JedisConnectFactory.getJedis();
//2.输入密码 auth
jedis.auth("123321");
//3.选择库
jedis.select(0);
}
//redis操作
@Test
public void testString(){
String result = jedis.set("name", "Jack");
System.out.println(result);
String name = jedis.get("name");
System.out.println(name);
}
//关闭资源
@AfterEach
public void tearDown(){
//健壮性判断
if (jedis != null){
jedis.close();
}
}
}
这里提一嘴,关闭资源依然是jedis.close 方法,但是,底层变成了归还线程池
3 SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:Spring Data Redis
-
提供了对不同Redis客户端的整合(Lettuce和Jedis)
-
提供了RedisTemplate统一API来操作Redis
-
支持Redis的发布订阅模型
-
支持Redis哨兵和Redis集群
-
支持基于Lettuce的响应式编程
-
支持基于JDK.JSON.字符串.Spring对象的数据序列化及反序列化
-
支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
3.1快速入门
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:
1.导入依赖坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.heima</groupId>
<artifactId>redis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 配置( redis springboot中的application.yaml文件 )
spring:
redis:
host: 192.168.110.128
port: 6379
password: 123321
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 1000ms
3. 测试代码
@SpringBootTest
class RedisDemoApplicationTests {
//注入RedisTemplate
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
void testString() {
// 写入一条String数据
redisTemplate.opsForValue().set("name", "虎哥");
// 获取string数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
}
3.2ReisTemplate配置序列化工具
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:
其实这个就是之前写入的 name:虎哥,只不过被序列化成了这个样子。
为了方便我们的可读性,还有释放内存空间,我们要对RedisTemplate进行配置序列化方式
代码如下:
package com.itheima.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* @Author 华子
* @Date 2022/11/19 19:47
* @Version 1.0
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//1.创建RedisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//2.设置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
//3.创建序列化工具
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//4.设置序列化工具
//设置key
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
//设置value
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
//5.返回
return redisTemplate;
}
}
这样我们在重新运行,就会正常啦~
那么,问题来了,如果传入的是Java对象呢?能不能可以正常的序列化?
直接试一试:
新建一个实体类User
package com.itheima.redis.pojo;
import lombok.Data;
/**
* @Author 华子
* @Date 2022/11/19 19:57
* @Version 1.0
*/
@Data
public class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public User() {
}
}
传入User对象
@Test
void testObject(){
User user = new User("华子",21);
redisTemplate.opsForValue().set("user:100",user);
User userInfo = (User) redisTemplate.opsForValue().get("user:100");
System.out.println(userInfo);
}
依然可以成功序列化Json对象,并且里面还有一个参数,实体类标识,这是用于读取的时候反序列化Java对象的~
3.3 StringRedisTemplate
尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:
为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
为了减少内存的消耗,我们可以采用手动序列化的方式,换句话说,就是不借助默认的序列化器,而是我们自己来控制序列化的动作,同时,我们只采用String的序列化器,这样,在存储value时,我们就不需要在内存中就不用多存储数据,从而节约我们的内存空间
代码就变成了如下方式(添加了手动序列化和反序列化)
package com.itheima;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.itheima.redis.pojo.User;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;
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.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
@SpringBootTest
class StringRedisTemplateTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testString() {
stringRedisTemplate.opsForValue().set("name","小帅");
String name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
// 创建对象
User user = new User("虎哥", 21);
// 手动序列化
String json = mapper.writeValueAsString(user);
// 写入数据
stringRedisTemplate.opsForValue().set("user:200", json);
// 获取数据
String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
// 手动反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println("user1 = " + user1);
}
}
这样就可以不用占内存啦~