# 四、Redis 客户端

# 1. Java 操作 Redis

Redis 的 Java 客户端也有很多:https://redis.io/clients#java,其中比较受欢迎的是 JedisLettuce

  • Jedis 在实现上是直接连接的 redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个 Jedis 实例增加物理连接,官方推荐。
  • Lettuce 的连接是基于 Netty 的, 连接实例(StatefulRedisConnection)可以在多个线程间并发访问,因为 StatefulRedisConnection 是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计, 一个连接实例不够的情况也可以按需增加连接实例。
  • 在 SpringBoot Data Redis 1.x 之前默认使用的是 Jedis,但目前最新版的修改成了 Lettuce。
  • 之前公司使用 Jedis 居多,Lettuce 近两年在逐步上升,总的来讲 Jedis 的性能会优于 Lettuce(因为它是直接操作Redis)。

# 1.1 环境准备

  • 创建 Maven 项目

  • 引入依赖坐标

    <!-- jedis 客户端 -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.6.0</version>
    </dependency>
    <!-- junit 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
    

# 1.2 代码演示

package com.hedon;

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

public class JedisTest {

    Jedis jedis = null;

    // 初始化
    @Before
    public void testInit(){
        // 初始化 Jedis 客户端,声明主机号和端口
        jedis = new Jedis("121.4.146.25", 6379);
        // 身份认证
        jedis.auth("123456");
        // 心跳机制,检测是否连接成功
        String pong = jedis.ping();
        System.out.println("pong = " + pong);
    }

    // 操作 Redis
    @Test
    public void test() {
        if (jedis == null) {
            return;
        }
        // 选择数据库
        String select = jedis.select(2);
        System.out.println("select = " + select);
        // 插入数据
        String result = jedis.set("username", "zhangsan");
        System.out.println("result = " + result);
        // 获取数据
        result = jedis.get("username");
        System.out.println("result = " + result);

    }

    // 释放资源
    @After
    public void testClose() {
        if (jedis != null) {
            // 释放资源
            jedis.close();
        }
    }
}

输出:

pong = PONG
select = OK
result = OK
result = zhangsan

# 1.3 Jedis 连接池优化

  • 封装 JedisPool 工具类

    package com.hedon;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    /**
     * Redis 连接池
     */
    public class JedisPoolConnectRedis {
    
    
        private static JedisPool jedisPool;
    
        // 创建连接池配置对象
        static {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 设置最大连接数,默认值是 8
            jedisPoolConfig.setMaxTotal(5);
            // 设置最大空闲数量,默认是 8
            jedisPoolConfig.setMaxIdle(5);
            // 设置最少空闲数,默认是 0
            jedisPoolConfig.setMinIdle(0);
            // 设置等待时间 ms
            jedisPoolConfig.setMaxWaitMillis(100);
            // 初始化 JedisPool
            jedisPool = new JedisPool(jedisPoolConfig, "121.4.146.25", 6379, 100, "123456");
        }
    
        // 静态方法
        public static Jedis getJedis(){
            return jedisPool.getResource();
        }
    
    }
    
  • 测试

    package com.hedon;
    
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import redis.clients.jedis.Jedis;
    import java.util.Set;
    
    public class JedisPoolTest {
    
        Jedis jedis = null;
    
        // 初始化
        @Before
        public void testInit(){
            // 初始化 Jedis 客户端,声明主机号和端口
            jedis = JedisPoolConnectRedis.getJedis();
            // 身份认证
            jedis.auth("123456");
            // 心跳机制,检测是否连接成功
            String pong = jedis.ping();
            System.out.println("pong = " + pong);
        }
    
        // 操作 Redis
        @Test
        public void test() {
            if (jedis == null) {
                return;
            }
            // 选择数据库
            String select = jedis.select(2);
            System.out.println("select = " + select);
            // 插入数据
            String result = jedis.set("username", "zhangsan");
            System.out.println("result = " + result);
            // 获取数据
            result = jedis.get("username");
            System.out.println("result = " + result);
            Set<String> keys = jedis.keys("*");
            System.out.println("keys = " + keys);
    
        }
    
    
        // 释放资源
        @After
        public void testClose() {
            if (jedis != null) {
                // 释放资源
                jedis.close();
            }
        }
    }
    

# 2. SpringBoot 集成 Redis

# 2.1 环境准备

  • 创建 SpringBoot 项目

  • 添加依赖坐标

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  • application.yaml 配置文件中配置 Redis

    spring:
      redis:
        host: 121.4.146.25
        port: 6379
        password: 123456
        database: 5
        # jedis 连接池版本
        jedis:
          pool:
            max-active: 8
            max-idle: 8
            min-idle: 0
            max-wait: 300
        # lettuce 连接池版本
    #    lettuce:
    #      pool:
    #        max-active: 8
    #        max-idle: 8
    #        min-idle: 0
    #        max-wait: 300
    
  • 在主启动器内添加 Redis 序列化方法

    package com.example.redisspringboot;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @SpringBootApplication
    public class RedisSpringbootApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(RedisSpringbootApplication.class, args);
        }
    
    
        /**
         * redisTemplate 序列化使用的 jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
         *
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
    
            // 使用 Jackson2JsonRedisSerialize 替换默认序列化
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
    
            // 设置 key 和 value 的序列化规则
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    }
    

# 2.2 代码演示

package com.example.redisspringboot;

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.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

@SpringBootTest(classes = {RedisSpringbootApplication.class})
class RedisSpringbootApplicationTests {

    // 注入模板对象
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testRedis(){
        System.out.println(redisTemplate.getConnectionFactory().getConnection().ping());
        // 获取 Redis 操作对象
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 插入数据
        valueOperations.set("username", "hedon");
        // 获取数据
        Object username = valueOperations.get("username");
        System.out.println("username = " + username);
    }

}

输出:

PONG
username = hedon

# 3. Golang 操作 Redis

# 4. Node.js 操作 Redis

# 5. Python 操作 Redis

上次更新: 7/28/2021, 2:41:58 PM