【Introduction to Redis】|Redis Java client

Table of contents

One: Redis Java client

1. Jedis Quick Start

2. Jedis connection pool

3. Spring Data Redis quick start

4. RedisSerializer configuration

5. StringRedisTemplate


One: Redis Java client

Clients in various languages ​​are provided on the Redis official website, address: redis.io/resources/c…

Jedis: Redis command is used as the method name, which is simple and practical with low learning cost. However, the Jedis instance is not thread-safe, and it needs to be used based on the connection pool in a multi-threaded environment.

lettuce: lettuce is implemented based on Netty, supports synchronous, asynchronous and responsive programming, and is thread-safe. Support Redis sentry mode, cluster mode and pipeline mode.

Redission: Redisson is a distributed and scalable collection of Java data structures based on Redis. Contains powerful functions such as Map, Queue, Lock, Semaphore, AtomicLong, etc.

​edit

1. Jedis Quick Start

The official website address of Jedis: github.com/redis/jedis , let's start with a quick start:

(1) Introduce dependencies

<!--jedis依赖-->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>3.7.0</version>
</dependency>
<!--单元测试依赖-->
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
</dependency>
复制代码

(2) Establish a connection: direct alt+insert to generate the setUp method

Create a Jedis object, enter the IP and port; call the auth() method to enter the password, and call the select() method to select the database!

@Before
public void setUp() throws Exception {
    // 建立接连
    jedis = new Jedis("192.168.2.129",6379);
    // 设置密码
    jedis.auth("123456");
    // 选择库
    jedis.select(0);
}
复制代码

(3) Perform operation test: directly alt+insert to generate the test method, and manually modify the method name

Note: For Jedis, the method called in the method body is actually a command in redis!

@Test
public void testString() {
   // 存数据
   String set = jedis.set("name", "张三");
   System.out.println("set = " + set);
   // 取数据
   String name = jedis.get("name");
   System.out.println("name = " + name);
}
复制代码

(4) Release resources: direct alt+insert to generate tearDown method

@After
public void tearDown() throws Exception {
   if (jedis != null) {
        jedis.close();
   }
}
复制代码

Specific code:

package com.zl.jedis;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

public class JedisTest {
    private Jedis jedis;

    // 建立连接
    @Before
    public void setUp() throws Exception {
        // 建立接连
        jedis = new Jedis("192.168.2.129",6379);
        // 设置密码
        jedis.auth("123456");
        // 选择库
        jedis.select(0);
    }

    // 操作
    @Test
    public void testString() {
        // 存数据
        String set = jedis.set("name", "张三");
        System.out.println("set = " + set);
        // 取数据
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }

    @After
    public void tearDown() throws Exception {
        if (jedis != null) {
            jedis.close();
        }
    }
}
复制代码

Results of the:

​edit

2. Jedis connection pool

Jedis itself is not thread-safe, and frequently creating and destroying connections will cause performance loss, so it is recommended that you use the Jedis connection pool instead of the direct connection method of Jedis!

①首先定义一个工具类JedisConnectionFactory类,用来获取Jedis连接池对象;

②定义一个静态的成员变量JedisPool(jedis连接池);

③在静态代码块中,创建JedisPoolConfig对象(jedis的一些配置),并配置一些基本信息;

④创建jedis连接池对象JedisPool,参数就是JedisPoolConfig对象、IP、端口、密码等信息;

⑤最终调用JedisPool对象的getResource方法,获取连接池对象。

package com.zl.util;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisConnectionFactory {
    private static final JedisPool jedisPool;

    static {
        // 配置连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大连接
        jedisPoolConfig.setMaxTotal(8);
        // 最大空闲连接
        jedisPoolConfig.setMaxIdle(8);
        // 最小空闲连接
        jedisPoolConfig.setMinIdle(0);
        // 设置最长等待时间
        jedisPoolConfig.setMaxWaitMillis(1000);
        // 创建连接池
        jedisPool = new JedisPool(jedisPoolConfig, "192.168.2.129", 6379, 1000, "123456");
    }

    // 获取Jedis对象
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }
}
复制代码

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封装到了不同的类型中(相对于直接使用jredis进行分组了):

API 返回值类型 说明
redisTemplate.opsForValue() ValueOperations 操作String类型数据
redisTemplate.opsForHash() HashOperations 操作Hash类型数据
redisTemplate.opsForList() ListOperations 操作List类型数据
redisTemplate.opsForSet() SetOperations 操作Set类型数据
redisTemplate.opsForZSet() ZSetOperations 操作SortedSet类型数据
redisTemplate 通用的命令

SpringBoot已经提供了对SpringDataRedis的支持,SpringDataRedis的使用步骤:

①引入spring-boot-starter-data-redis起步依赖;

②在application.yml配置Redis信息;

③注入RedisTemplate;

(1)引入依赖

<!--Redis起步依赖-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>
<!--连接池依赖,无论是Jedis还是lettcue都是基于连接池的-->
  <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
  </dependency>
复制代码

(2)application.yml配置文件

注: Spring默认引入的是lettuce,要想使用jedis还要引入jedis的依赖;但是无论是lettuce还是jedis都是基于连接池创建连接的,所以需要前面的commons-pool2连接池依赖。

spring:
  redis:
    host: 192.168.2.129
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8 #最大连接
        max-idle: 8 #最大空闲连接
        min-idle: 0 #最小空闲连接
        max-wait: 100 #连接等待时间
复制代码

(3)注入RedisTemplate并测试

package com.zl;

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;

@SpringBootTest
class SpringDataRedisApplicationTests {
    // 注入RedisTemplate
    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    void testString() {
        // 插入数据,参数不仅仅是字符串,Java对象也可以
        redisTemplate.opsForValue().set("name","小红");
        // 获取数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);

    }

}
复制代码

执行结果:

​编辑

4. RedisSerializer配置

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

​编辑

实际上这个key和value就是我们前面存入的小红(序列化后的结果);SpringDataRedis可以接收任何对象,怎么实现的?就是通过对象的数据进行序列化及反序列化!

从哪里可以看出是使用了JDK的序列化方式

​编辑

缺点:

①可读性差;

②内存占用较大;

有其它的序列化方式吗?

①JdkSerializationRedisSerializer: 使用JDK的序列化方式,前面我们已经用过了!

②StringRedisSerializer: 专门处理字符串的类型,例如key基本上都是字符串!

③GenericJackson2JsonRedisSerializer: 如果value是对象,建议使用这个!

怎样做到,所存即所得呢?我们可以自定义RedisTemplate的序列化方式,代码如下:

package com.zl.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
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;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        // 创建RedisTemplate对象
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        // 连接工厂,这个工厂springboot会帮我们创建好
        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;
    }

}
复制代码

其中RedisSerializer的string()方法就是使用了StringRedisSerializer的一个常量

​编辑

因为使用了JSON序列化工具,所以还要引入JSON依赖

<!--引入Jackson依赖-->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
</dependency>
复制代码

再次进行测试

package com.zl;

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;

@SpringBootTest
class SpringDataRedisApplicationTests {
    // 注入RedisTemplate
    @Autowired
    private RedisTemplate<String,Object> redisTemplate; // 引用泛型


    @Test
    void testString() {
        // 插入数据,参数不仅仅是字符串,Java对象也可以
        redisTemplate.opsForValue().set("name","小红");
        // 获取数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);

    }

}
复制代码

执行结果:

​编辑

思考:如果使用Java对象呢?

 给定一个User对象

package com.zl.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


// 使用以下注解需要引入lombok依赖
@Data // setter and getter
@NoArgsConstructor // 无参构造
@AllArgsConstructor  // 有参构造
public class User {
    private String name;
    private Integer age;
    
}
复制代码

进行测试

package com.zl;

import com.zl.pojo.User;
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;

@SpringBootTest
class SpringDataRedisApplicationTests {
    // 注入RedisTemplate
    @Autowired
    private RedisTemplate redisTemplate; // 引用泛型


    @Test
    void testSaveUser() {
        // 插入数据
        redisTemplate.opsForValue().set("user",new User("张三",18));
        // 取出数据
        User user = (User) redisTemplate.opsForValue().get("user");
        System.out.println("user = " + user);
    }
}
复制代码

执行结果:

​编辑

图形界面客户端:

自动的把Java对象转换为JSON写入,当获取结果的时候也能反序列化为User对象;实际上在写入JSON的同时,把User的字节码名称也写进去了com.zl.pojo.User,通过这个属性在反序列化的时候转换成User对象!

注: 为了在反序列化时知道对象的类型,不仅仅写了User对象的属性,还把类的class类型写入了Json结果中,存入redis,会带来额外的内存开销。

​编辑

5. StringRedisTemplate

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

​编辑

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

所以,现在最重要的就是处理Java对象,手动序列化和反序列

(1) Use the JSON tool ObjectMapper (SpringMVC processing Json tool): call the writeValuesString() method of the ObjectMapper object to manually complete the serialization, convert the string into json format and store it in redis; call the readValue() method of the ObjectMapper object to manually complete the deserialization Transformation, converted into a Java object!

(2) You can also use fastjson, which is Alibaba's open-source JSON parsing library , which requires the introduction of fastjon dependencies. Then call JSON's toJSONString() method to convert it into a string in json format; call JSON's parseObject() method to convert it into a Java object!

package com.zl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zl.pojo.User;
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.StringRedisTemplate;


@SpringBootTest
class ApplicationTest {
    // 注入StringRedisTemplate
    @Autowired
    private StringRedisTemplate stringredisTemplate;
    // JSON工具
    private static final ObjectMapper mapper = new ObjectMapper(); // ObjectMapper是SpringMVC处理Json的工具
    // fastjson是阿里巴巴的开源JSON解析库


    @Test
    void testString() {
        // 对于普通字符串步骤不变
        stringredisTemplate.opsForValue().set("name","小红");
        Object name = stringredisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);

    }

    @Test
    void testSaveUser() throws JsonProcessingException {
        // 对于Java对象加上手动转步骤
        // 准备Java对象
        User user = new User("虎哥", 18);
        // 手动序列化
        // String json = mapper.writeValueAsString(user); // 把Java对象转换成Json格式的字符串
        String json = JSON.toJSONString(user);
        // 写入redis
        stringredisTemplate.opsForValue().set("user",json);
        // 读取数据
        String val = stringredisTemplate.opsForValue().get("user"); // 读出来的是Json格式的字符串
        // 反序列化
        // User user1 = mapper.readValue(val, User.class);
        User user1 = JSON.parseObject(val, User.class);
        System.out.println("user1 = " + user1);


    }
}
复制代码

Results of the:

​edit

GUI client:

​edit

Supplement: For other types of structures, it may be more biased towards the way JavaAPI is written, for example: Hash structure

① For storing data, instead of using the hset() method, the command name is not used as the method name in Spring, because it is similar to the HashMap structure in Java, so the method name is consistent with the HashMap structure, and the put() method is used for access .

②For fetching data, instead of using hget, use the get() method to fetch a single entry, and if fetching multiple entries, use the entrys() method.

@Test
void testHash() {
    // 插入数据
    stringredisTemplate.opsForHash().put("user:100","name","张三");
    stringredisTemplate.opsForHash().put("user:100","age","18");
    // 取出数据
    Object name = stringredisTemplate.opsForHash().get("user:100", "name"); // 取一个
    Map<Object, Object> entries = stringredisTemplate.opsForHash().entries("user:100");
    System.out.println("entries = " + entries); // 取所有

}
复制代码

Summarize the two serialization practices of RedisTemplate:

Option One:

① Customize RedisTemplate

② Modify the serializer of RedisTemplate to GenericJackson2JsonRedisSerializer

Option II:

① Use String Redis Template

② When writing to Redis, manually serialize the object into JSON; when reading Redis, manually deserialize the read JSON into an object

Guess you like

Origin juejin.im/post/7230323430129483813