Redis中的Java客户端

一、Jedis

Jedis是一个Java实现的Redis客户端连接工具。

Jedis使用非常简单,直接引入依赖。基于默认参数的Jedis连接池,初始化连接池类(使用默认连接池参数)JedisPool,获取一个Jedis连接Jedis jedis=jp.getResource()。

Jedis是线程不安全的,多线程使用同一个Jedis实例,会出现并发问题,原因是底层共用了一个输入输出流

1.1 Jedis快速入门

Jedis的官网地址: GitHub - redis/jedis: Redis Java client,我们先来个快速入门:

① 新建一个Maven工程并引入以下依赖

复制代码
<!--引入Jedis依赖-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.2.0</version>
</dependency>

<!--引入单元测试依赖-->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

编写测试类并与Redis建立连接

复制代码
private Jedis jedis;

@BeforeEach //被该注解修饰的方法每次执行其他方法前自动执行
void setUp(){
    // 1. 获取连接
    jedis = new Jedis("192.168.230.88",6379);
    // 2. 设置密码
    jedis.auth("132537");
    // 3. 选择库(默认是下标为0的库)
    jedis.select(0);
}

编写一个操作数据的方法(这里以操作String类型为例)

复制代码
@Test
public void testString(){
    // 1.往redis中存放一条String类型的数据并获取返回结果
    String result = jedis.set("url", "https://www.oz6.cn");
    System.out.println("result = " + result);

    // 2.从redis中获取一条数据
    String url = jedis.get("url");
    System.out.println("url = " + url);
}

最后不要忘记编写一个释放资源的方法

复制代码
    @AfterEach //被该注解修饰的方法会在每次执行其他方法后执行
    void tearDown(){
        // 1.释放资源
        if (jedis != null){
            jedis.close();
        }
    }

执行testString()方法后测试结果如图所示

1.2 Jedis连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式

复制代码
public class JedisConnectionFactory {
    private static final JedisPool jedisPool;

    static {
        //配置连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(8);
        jedisPoolConfig.setMaxIdle(8);
        jedisPoolConfig.setMinIdle(0);
        jedisPoolConfig.setMaxWaitMillis(200);
        //创建连接池对象
        jedisPool = new JedisPool(jedisPoolConfig,"192.168.230.88",6379,1000,"132537");
    }

    public static Jedis getJedis(){
       return jedisPool.getResource();
    }
}

二、SpringDataRedis介绍

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis

官网地址Spring Data Redis

  • 提供了对不同Redis客户端的整合(LettuceJedis

  • 提供了RedisTemplate统一API来操作Redis

  • 支持Redis的发布订阅模型

  • 支持Redis哨兵和Redis集群

  • 支持基于Lettuce的响应式编程

  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化

  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

三、SpringDataRedis快速入门

SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单

首先新建一个Spring Boot工程

然后引入连接池依赖

复制代码
<!--连接池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

编写配置文件application.yml(连接池的配置在实际开发中是根据需求来的)

复制代码
spring:
  redis:
    host: 192.168.230.88 #指定redis所在的host
    port: 6379  #指定redis的端口
    password: 132537  #设置redis密码
    lettuce:
      pool:
        max-active: 8 #最大连接数
        max-idle: 8 #最大空闲数
        min-idle: 0 #最小空闲数
        max-wait: 100ms #连接等待时间

编写测试类执行测试方法

复制代码
@SpringBootTest
class RedisDemoApplicationTests {

	@Resource
	private RedisTemplate redisTemplate;

	@Test
	void testString() {
		// 1.通过RedisTemplate获取操作String类型的ValueOperations对象
		ValueOperations ops = redisTemplate.opsForValue();
		// 2.插入一条数据
		ops.set("blogName","Vz-Blog");
		
		// 3.获取数据
		String blogName = (String) ops.get("blogName");
		System.out.println("blogName = " + blogName);
	}
}

四、RedisSerializer配置

RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的

缺点:

  • 可读性差

  • 内存占用较大

那么如何解决以上的问题呢?我们可以通过自定义RedisTemplate序列化的方式来解决。

编写一个配置类RedisConfig :

复制代码
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        // 1.创建RedisTemplate对象
        RedisTemplate<String ,Object> redisTemplate = new RedisTemplate<>();
        // 2.设置连接工厂
        redisTemplate.setConnectionFactory(factory);

        // 3.创建序列化对象
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

        // 4.设置key和hashKey采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);

        // 5.设置value和hashValue采用json的序列化方式
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);

        return redisTemplate;
    }
}

此时我们已经将RedisTemplate的key设置为String序列化,value设置为Json序列化的方式,再来执行方法测试

由于我们设置的value序列化方式是Json的,因此我们可以直接向redis中插入一个对象

复制代码
@Test
void testSaveUser() {
    redisTemplate.opsForValue().set("user:100", new User("Vz", 21));
    User user = (User) redisTemplate.opsForValue().get("user:100");
    System.out.println("User = " + user);
}

尽管Json序列化可以满足我们的需求,但是依旧存在一些问题。

如上图所示,为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。

那么我们如何解决这个问题呢?我们可以通过下文的StringRedisTemplate来解决这个问题。

五、StringRedisTemplate

为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程

我们可以直接编写一个测试类使用StringRedisTemplate来执行以下方法:

复制代码
@SpringBootTest
class RedisStringTemplateTest {

	@Resource
	private StringRedisTemplate stringRedisTemplate;

	@Test
	void testSaveUser() throws JsonProcessingException {
		// 1.创建一个Json序列化对象
		ObjectMapper objectMapper = new ObjectMapper();
		// 2.将要存入的对象通过Json序列化对象转换为字符串
		String userJson1 = objectMapper.writeValueAsString(new User("Vz", 21));
		// 3.通过StringRedisTemplate将数据存入redis
		stringRedisTemplate.opsForValue().set("user:100",userJson1);
		// 4.通过key取出value
		String userJson2 = stringRedisTemplate.opsForValue().get("user:100");
		// 5.由于取出的值是String类型的Json字符串,因此我们需要通过Json序列化对象来转换为java对象
		User user = objectMapper.readValue(userJson2, User.class);
		// 6.打印结果
		System.out.println("user = " + user);
	}

}

执行完毕回到Redis的图形化客户端查看结果

六、总结

RedisTemplate的两种序列化实践方案,两种方案各有各的优缺点,可以根据实际情况选择使用。

方案一:

  1. 自定义RedisTemplate

  2. 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer

方案二:

  1. 使用StringRedisTemplate

  2. 写入Redis时,手动把对象序列化为JSON

  3. 读取Redis时,手动把读取到的JSON反序列化为对象

相关推荐
东阳马生架构13 分钟前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖27 分钟前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南30 分钟前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
九皇叔叔39 分钟前
【7】PostgreSQL 事务
数据库·postgresql
DKPT40 分钟前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
kk在加油42 分钟前
Mysql锁机制与优化实践以及MVCC底层原理剖析
数据库·sql·mysql
Percep_gan1 小时前
idea的使用小技巧,个人向
java·ide·intellij-idea
缘来是庄1 小时前
设计模式之迭代器模式
java·设计模式·迭代器模式
Liudef061 小时前
基于HTML与Java的简易在线会议系统实现
java·前端·html
Kookoos1 小时前
ABP VNext + Cosmos DB Change Feed:搭建实时数据变更流服务
数据库·分布式·后端·abp vnext·azure cosmos