【Redis】初识Redis:如何在Java程序中使用Redis?

初识Redis:如何在Java程序中使用Redis?

在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/clients/

其中也包含很多Java客户端:

【Redis】初识Redis:如何在Java程序中使用Redis?_第1张图片

常用的Java客户端有Jedis、Lettuce和Redisson

  • Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而SpringDataRedis又对这两种做了抽象和封装,因此我们一般都是直接学习SpringDataRedis
  • Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。

1 Jedis客户端

Jedis的官网地址: https://github.com/redis/jedis

1.1 Jedis快速入门

1)创建一个普通的maven项目,引入依赖:


<dependency>
    <groupId>redis.clientsgroupId>
    <artifactId>jedisartifactId>
    <version>3.7.0version>
dependency>

<dependency>
    <groupId>org.junit.jupitergroupId>
    <artifactId>junit-jupiterartifactId>
    <version>5.7.0version>
    <scope>testscope>
dependency>

2)新建一个单元测试类,内容如下:

/**
 * Jedis测试类
 */
public class JedisTest {

    private Jedis jedis;

    /**
     * 建立Redis连接,初始化jedis
     */
    @BeforeEach
    public void setUp(){
        // 1.建立连接,参数需要填自己虚拟机的地址与Redis的端口号
        jedis = new Jedis("192.168.211.100", 6379);
        // 2.Redis连接密码
        jedis.auth("123456");
        // 3.选择使用Redis中的哪个库
        jedis.select(0);
    }

    /**
     * 测试string类型的基本使用
     */
    @Test
    public void testString(){
        jedis.set("name", "张三");
        String name = jedis.get("name");
        System.out.println(name); 
    }

    /**
     * 测试hash类型的基本使用
     */
    @Test
    public void testHash(){
        jedis.hset("user","name","李四");
        String name = jedis.hget("user", "name");
        System.out.println(name);
    }

    /**
     * 连接使用之后需要被释放
     */
    @AfterEach
    public void tearDown(){
        if(jedis != null){
            jedis.close();
        }
    }

}

可以看到,jedis的API与redis指令是比较相似的。

1.2 连接池

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

1)新建一个包,名为com.jedis.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.211.100", 6379, 1000, "123456");
    }

    /**
     * 设置静态方法,用于返回一个jedis连接
     * @return
     */
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
    
}

2)将测试类中建立redis连接的方法进行修改,其他代码不变:

/**
  * 建立Redis连接,初始化jedis
  */
@BeforeEach
public void setUp(){
    // 1.建立连接,参数需要填自己虚拟机的地址与Redis的端口号
    // jedis = new Jedis("192.168.211.100", 6379);

    // 1.通过jedis连接工厂获取jedis连接
    jedis = JedisConnectionFactory.getJedis();
    // 2.选择使用Redis中的哪个库
    jedis.select(0);
    
}

2 SpringDataRedis客户端

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis,SpringData有如下特点:

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

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

【Redis】初识Redis:如何在Java程序中使用Redis?_第2张图片

在实际开发中,我们一般都会使用SpringDataRedis,而非jedis

2.1 SpringDataRedis快速入门

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

1)新建一个SpringBoot项目,并引入以下依赖:

<dependencies>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
    <dependency>
        <groupId>org.apache.commonsgroupId>
        <artifactId>commons-pool2artifactId>
    dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.coregroupId>
        <artifactId>jackson-databindartifactId>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombokgroupId>
                        <artifactId>lombokartifactId>
                    exclude>
                excludes>
            configuration>
        plugin>
    plugins>
build>

2)在application.yml中添加以下配置

spring:
  redis:
    # 配置连接信息
    host: 192.168.211.100
    port: 6379
    password: 123456
    # 配置连接池信息
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms

3)在测试类中编写测试代码

@SpringBootTest
class RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testString(){
        //写入一条string类型的数据
        redisTemplate.opsForValue().set("name","张三");
        //获取一条string类型的数据
        Object name = redisTemplate.opsForValue().get("name");
        
        System.out.println(name);
    }

}

2.2 自定义序列化

当我们在执行上述代码之后,点开redis图形界面客户端,发现插入的string类型的数据变成了这样:

在这里插入图片描述

这显然与我们插入的键值对不符合,但是当我们获取键为name的值并打印之后,发现结果又是正常的

【Redis】初识Redis:如何在Java程序中使用Redis?_第3张图片

这又是为什么呢?

不知道各位小伙伴有没有注意到,当我们在使用redisTemplate操作string数据类型时,其api允许我们使用object类型的对象作为key或者value

【Redis】初识Redis:如何在Java程序中使用Redis?_第4张图片

但是我们知道,string类型的key和value在redis当中应该都是字符串才对,那为什么redisTemplate允许我们使用object类型呢?其底层又做了什么样的处理呢?

其实redisTemplate将Object写入redis之前,会先将object序列化为字节形式,默认是采用JDK序列化,而JDK序列化之后得到的结果就是我们刚刚看到的这个样子

在这里插入图片描述

这种序列化方式的缺点是很明显的,比如内存占用大,可读性差等等。

redisTemplate允许我们对序列化方式进行自定义,并提供了几种序列化器供我们使用,常见的序列化器有以下几种

【Redis】初识Redis:如何在Java程序中使用Redis?_第5张图片

常用的是 StringRedisSerializer 和 GenericJackson2JsonRedisSerializer , StringRedisSerializer是专门用来处理String类型,将String类型转为字节数组的序列化器,而GenericJackson2JsonRedisSerializer 是将对象转为json串的的序列化器

我们可以自定义RedisTemplate的序列化方式,代码如下:

@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;
    }
}

再执行以下代码:

@Test
public void testString(){
    //写入一条string类型的数据
    redisTemplate.opsForValue().set("name","张三");
    //获取一条string类型的数据
    Object name = redisTemplate.opsForValue().get("name");

    System.out.println(name);
}

在这里插入图片描述

结果正常,这样才是我们想要看到的样子。

如果我们插入的是一个对象而不是字符串,那么又能否插入成功呢?来测试一下:

@Test
public void testStringObject(){
    //写入一条string类型的数据,值类型为Date
    redisTemplate.opsForValue().set("birthday",new Date());

    Object birthday = redisTemplate.opsForValue().get("birthday");

    System.out.println(birthday);

}

打印结果正常

【Redis】初识Redis:如何在Java程序中使用Redis?_第6张图片

打开图形化客户端再看看

【Redis】初识Redis:如何在Java程序中使用Redis?_第7张图片

结果也是正常的,因为我们使用了JSON序列化来代替默认的JDK序列化方式,整体可读性有了很大提升。我们还发现保存的json串中还带有该json的类型,这是因为无论是java对象的序列化还是反序列化,都是redisTemplate帮我们自动完成的,因此redisTemplate在对对象进行序列化时必须将该java对象的类型一并保存下来,但是这样的话就带来了额外的内存开销,针对这种问题有没有解决方案呢?

2.3 StringRedisTemplate

为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。如果我们需要存储Java对象,就手动对java对象进行序列化或反序列化处理

【Redis】初识Redis:如何在Java程序中使用Redis?_第8张图片

因为存入和读取时的序列化及反序列化都是我们自己实现的,SpringDataRedis就不会将class信息写入Redis了。

那我们现在变更了序列化器,是否需要重新定义一下RedisTemplate的序列化规则呢?答案是不用

由于这种用法比较普遍,所以SpringDataRedis提供了RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式。

演示如下,这里的序列化方式使用的是jackson

// 注入StringRedisTemplate
@Autowired
private StringRedisTemplate stringRedisTemplate;

// 定义JSON序列化工具
private static final ObjectMapper mapper = new ObjectMapper();

@Test
public void testStringRedisTemplate() throws JsonProcessingException {
    //手动序列化
    String now = mapper.writeValueAsString(new Date());

    stringRedisTemplate.opsForValue().set("now",now);

    String result = stringRedisTemplate.opsForValue().get("now");

    //手动反序列化
    Date date = mapper.readValue(result, Date.class);

    System.out.println(date);
}

再次查看图形化客户端,此时插入的数据中已经没有数据类型的相关信息了

【Redis】初识Redis:如何在Java程序中使用Redis?_第9张图片

你可能感兴趣的:(#,Redis,redis,java)