【QA】如何在Java中使用Redis

本文详细介绍了在Java中使用Jedis进行裸连、Jedis_pool实现连接池以及SpringDataRedis的RedisTemplate进行操作,涵盖了连接管理、数据存取、序列化与反序列化的相关内容。
摘要由CSDN通过智能技术生成

前言

以下涉及的代码均在Github上有完整记录。

GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程Java_Client_Redis

Java中应用Redis

方式1 | Jedis裸连

依赖引入

<!--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>

代码测试

package com.example;

public class AppTest {
    private Jedis jedis;
    @BeforeEach
    void setUp() {
        // 1.建立连接
         jedis = new Jedis("192.168.93.128", 6379);
        // 2.设置密码
        jedis.auth("123456");
        // 3.选择库
        jedis.select(0);
    }
    @Test
    void testString() {
        // 存入数据
        String result = jedis.set("name", "虎哥");
        System.out.println("result = " + result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }

    @Test
    void testHash() {
        // 插入hash数据
        jedis.hset("user:1", "name", "Jack");
        jedis.hset("user:1", "age", "21");

        // 获取
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);
    }

    @AfterEach
    void tearDown() {
        // 这里的close指关闭连接
        if (jedis != null) {
            jedis.close();
        }
    }
}

特点

每次调用,新建一个jedis线程,使用完毕后,关闭该线程。

jedis本身是线程不安全的,在多线程环境下,还是要用连接池来实现。

方式2 | Jedis_pool

依赖引入

<!--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>

代码 | 自定义连接池工具类

package com.example.util.jedis;

public class JedisConnectionFactory {
    private static JedisPool jedisPool;

    static {
        // 配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(8);
        poolConfig.setMaxIdle(8);
        poolConfig.setMinIdle(0);
        poolConfig.setMaxWaitMillis(1000);
        // 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码
        jedisPool = new JedisPool(poolConfig, "192.168.93.128", 6379, 1000, "123456");
    }

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

代码 | 测试

package com.example;

public class AppTest {
    private Jedis jedis;
    @BeforeEach
    void setUp() {
        // 1.建立连接
        jedis = JedisConnectionFactory.getJedis();
        // 2.设置密码
        jedis.auth("123456");
        // 3.选择库
        jedis.select(0);
    }
    @Test
    void testString() {
        // 存入数据
        String result = jedis.set("name", "虎哥");
        System.out.println("result = " + result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }

    @Test
    void testHash() {
        // 插入hash数据
        jedis.hset("user:1", "name", "Jack");
        jedis.hset("user:1", "age", "21");

        // 获取
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);
    }

    @AfterEach
    void tearDown() {
        // 这里的close指归还资源给线程池
        if (jedis != null) {
            jedis.close();
        }
    }
}

特点

  • 通过线程池,避免了线程的频繁创建和销毁,减少资源的消耗

方式3 | SpringDataRedis

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

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

调用RedisTemplate | SpringBoot默认的实现

常用API

image-20240103092412836

使用方式

依赖导入:SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件配置Redis:

  • 根据SpringBoot版本的不同,data这一层级的关系,在3.x版本中才出现,2.x版本没有
spring:
  data:
    redis:
      port: 6379
      host: 192.168.93.128
      password: 123456
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 0
          max-wait: 100ms
  • 测试
package com.example;

@SpringBootTest
class Demo03SpringDataRedisRedisTemplateApplicationTests {
   @Autowired
   private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        // 写入一条String数据
        redisTemplate.opsForValue().set("name", "虎哥");
        // 获取string数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }
}
特点

存入Redis的数据和原始数据不太一样。

调用RedisTemplate | 自定义实现方式

RedisTemplate存入Redis的数据与原数据展示形式不同,因为默认的set函数接受的参数是Object类型,默认进行了序列化操作。

若要实现数据写入和保存结果一致,可以自定义RedisTemplate,并注入到Spring容器里面,代替默认的。

自定义redisTemplate
package com.example.config;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);
        // 创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer =
                new GenericJackson2JsonRedisSerializer();
        // 设置Key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置Value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);
        // 返回
        return template;
    }
}
测试
package com.example;

@SpringBootTest
class Demo04SpringDataRedisRedisTemplateDiyApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testsaveString() {

        // 写入一条String数据
        redisTemplate.opsForValue().set("name", "虎哥");
        // 获取string数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }

    @Test
    void testsaveUser() {
        User user = new User("你好", 18);
        redisTemplate.opsForValue().set("user:100", user);
        User object = (User) redisTemplate.opsForValue().get("user:100");
        System.out.println(object);
    }
}

结果

image-20240103093534007

特点
  • 实现了自动序列化和反序列化,存入Redis的内容和原始内容一致
  • 代价就是有额外的内存开销。上述红框额外存入的内容比正式存入的内容所占内存还大

调用stringRedisTemplate | 手动序列化、反序列化

通过自定义redisTemplate,实现自动序列化和反序列化,并且key的存入保持原样。缺点就是有额外的内存开销

若要节省内存空间,就需要手动序列化和反序列化:自带的stringRedisTemplate就可以满足要求

StringRedisTemplate的源代码
package org.springframework.data.redis.core;

import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;

public class StringRedisTemplate extends RedisTemplate<String, String> {
    public StringRedisTemplate() {
        this.setKeySerializer(RedisSerializer.string());
        this.setValueSerializer(RedisSerializer.string());
        this.setHashKeySerializer(RedisSerializer.string());
        this.setHashValueSerializer(RedisSerializer.string());
    }

    public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
        this();
        this.setConnectionFactory(connectionFactory);
        this.afterPropertiesSet();
    }

    protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
        return new DefaultStringRedisConnection(connection);
    }
}

测试

package com.example;

@SpringBootTest
class Demo04SpringDataRedisStringRedisTemplateApplicationTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // JSON序列化工具
    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);
    }

    @Test
    void testHash(){
        stringRedisTemplate.opsForHash().put("user:400", "name", "胡歌");
        stringRedisTemplate.opsForHash().put("user:400", "age", "32");

        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:400");
        System.out.println(entries);
    }
}
特点
  • 优点:节省内存的同时,使得Redis数据库中存储的Key和Value跟实际的一样
  • 缺点:需要手动序列化和反序列化,比较麻烦
  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值