redis相关操作-springboot3整合-基础功能

我爱海鲸 2025-05-25 11:50:34 暂无标签

简介rank、排行榜

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.haijin</groupId>
    <artifactId>redis-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version> <!-- 使用最新的Spring Boot 3版本 -->
        <relativePath/>
    </parent>

    <properties>
        <java.version>17</java.version> <!-- Spring Boot 3需要Java 17+ -->
        <jedis.version>5.0.2</jedis.version>
        <commons-pool2.version>2.11.1</commons-pool2.version>
    </properties>

    <dependencies>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot Starter for Redis (排除默认的Lettuce) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Jedis Redis Client -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
        </dependency>

        <!-- Apache Commons Pool 2 (Jedis依赖) -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>${commons-pool2.version}</version>
        </dependency>

        <!-- JSON序列化支持 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        <!-- Lombok (可选) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>22.0</version>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.yml:

spring:
  redis:
    host: 192.168.3.10       # Redis服务器地址
    port: 6379            # Redis服务器端口
    password: 123456           # Redis密码,没有密码留空
    timeout: 2000         # 连接超时时间(毫秒)
    database: 0           # 使用的数据库索引(0-15)

    # Jedis连接池配置
    jedis:
      pool:
        max-active: 8      # 连接池最大连接数(使用负值表示没有限制)
        max-idle: 8        # 连接池中的最大空闲连接
        min-idle: 0        # 连接池中的最小空闲连接
        max-wait: -1ms     # 连接池最大阻塞等待时间(使用负值表示没有限制)

    # 高级配置(需要与您的JedisConfig类匹配)
    # 以下配置需要自定义属性绑定,标准spring.redis不直接支持
    test-on-borrow: false  # 在获取连接时检查连接有效性
    test-on-return: false  # 在归还连接时检查连接有效性

RedisHashVo:

package xyz.haijin.vo;

import redis.clients.jedis.Response;

/**
 * 2025/5/25.
 *
 * @author haijin
 */
public class RedisHashVo {

    private String key;
    private String field;
    private String value;
    private Response<String> response;

    public RedisHashVo() {
    }

    public RedisHashVo(String key, String field) {
        this.key = key;
        this.field = field;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Response<String> getResponse() {
        return response;
    }

    public void setResponse(Response<String> response) {
        this.response = response;
    }
}

RedisUtil:

package xyz.haijin.utils;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {
    private final RedisTemplate<String, Object> redisTemplate;

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // ==============================common============================

    /**
     * 指定缓存失效时间
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取过期时间
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 普通缓存获取
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}

JedisPoolManager:

package xyz.haijin.utils;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.List;

/**
 * 2025/5/25.
 *
 * @author haijin
 */
@Slf4j
public class JedisPoolManager {

    private static final ThreadLocal<JedisPool> CURRENT_JEDIS_POOL = new ThreadLocal<JedisPool>();

    private List<JedisPool> jedisPools;

    public Jedis getJedis() {
        for (int i = 0, size = jedisPools.size(); i < size; i++) {
            JedisPool jedisPool = jedisPools.get(i);
            Jedis jedis = null;
            try {

                jedis = jedisPool.getResource();
                if (jedis.isConnected()) {
                    CURRENT_JEDIS_POOL.set(jedisPool);
                    return jedis;
                } else {
                    jedis.close();
                    log.error("Get jedis connection from pool but not connected.");
                }
            } catch (JedisConnectionException e) {
                log.error("Get jedis connection from pool list index:{}", i, e);
                if (jedis != null) {
                    log.warn("Return broken resource:" + jedis);
                    log.info("jedis close bef");
                    jedis.close();
                }
            }
        }
        return null;
    }

    public void setJedisPools(List<JedisPool> jedisPools) {
        this.jedisPools = jedisPools;
    }
}

JedisService:

RedisDataAccessException:

package xyz.haijin.exception;

import org.springframework.dao.DataAccessException;

/**
 * 2025/5/25.
 *
 * @author haijin
 */
public class RedisDataAccessException extends DataAccessException {

    public RedisDataAccessException(String message) {
        super(message);
    }

    public RedisDataAccessException(String message, Throwable cause) {
        super(message, cause);
    }
}

JedisConfig:

package xyz.haijin.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
/**
 * Jedis 客户端配置类
 * 用于配置Redis连接参数和连接池参数
 */
public class JedisConfig {

    /**
     * Redis服务器主机地址
     * 默认值: localhost
     * 示例: 192.168.1.100
     */
    private String host;

    /**
     * Redis服务器端口号
     * 默认值: 6379
     */
    private int port;

    /**
     * 连接超时时间(毫秒)
     * 建议值: 2000-5000ms
     * 0表示无超时限制(不推荐)
     */
    private int timeout;

    /**
     * 连接池最大连接数
     * 建议值: 根据业务QPS调整(通常为QPS/1000 * 2)
     * 默认值: 8
     * -1表示无限制(不推荐)
     */
    private int maxTotal;

    /**
     * 连接池中最大空闲连接数
     * 建议值: maxTotal的50-70%
     * 默认值: 8
     */
    private int maxIdle;

    /**
     * 获取连接时的最大等待时间(毫秒)
     * 建议值: 1000-3000ms
     * 默认值: -1 (无限等待,不推荐)
     */
    private long maxWait;

    /**
     * 连接池中最小空闲连接数
     * 建议值: 根据业务低谷期流量设置
     * 默认值: 0
     */
    private int minIdle;

    /**
     * Redis服务器密码
     * 注意: 生产环境必须设置
     * 格式:
     * - 无密码: null或空字符串
     * - 有密码: 实际密码字符串
     */
    private String password;

    /**
     * 从连接池获取连接时是否校验连接有效性
     * 开启后会降低性能但能避免拿到失效连接
     * 建议值: 生产环境true,开发环境false
     */
    private boolean testOnBorrow;

    /**
     * 归还连接到连接池时是否校验连接有效性
     * 开启后会降低性能但能保证连接池中连接可用
     * 建议值: 生产环境true,开发环境false
     */
    private boolean testOnReturn;
}

RedisAutoConfiguration:

package xyz.haijin.autoconfigure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import xyz.haijin.config.JedisConfig;
import xyz.haijin.utils.JedisPoolManager;

import java.util.Collections;

/**
 * 2025/5/25.
 *
 * @author haijin
 */
@Configuration
@DependsOn("jedisConfig")
@ConditionalOnClass({Jedis.class})
public class RedisAutoConfiguration {

    @Autowired
    private JedisConfig redisConfig;

    @Bean("writeJedisPoolManager")
    public JedisPoolManager writeJedisPoolManager() {
        JedisPoolManager jedisPoolManager = new JedisPoolManager();
        jedisPoolManager.setJedisPools(Collections.singletonList(this.writeJedisPoolMaster()));
        return jedisPoolManager;
    }

    @Bean("readJedisPoolManager")
    public JedisPoolManager readJedisPoolManager() {
        JedisPoolManager jedisPoolManager = new JedisPoolManager();
        jedisPoolManager.setJedisPools(Collections.singletonList(this.readJedisPoolMaster()));
        return jedisPoolManager;
    }


    private JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(this.redisConfig.getMaxIdle());
        config.setMaxTotal(this.redisConfig.getMaxTotal());
        config.setMaxWaitMillis(this.redisConfig.getMaxWait());
        config.setMinIdle(this.redisConfig.getMinIdle());
        config.setTestOnReturn(this.redisConfig.isTestOnReturn());
        config.setTestOnBorrow(this.redisConfig.isTestOnBorrow());
        return config;
    }

    private JedisPool writeJedisPoolMaster() {
        return new JedisPool(this.jedisPoolConfig(), this.redisConfig.getHost(), this.redisConfig.getPort(), this.redisConfig.getTimeout(), this.redisConfig.getPassword());
    }

    private JedisPool readJedisPoolMaster() {
        return new JedisPool(this.jedisPoolConfig(), this.redisConfig.getHost(), this.redisConfig.getPort(), this.redisConfig.getTimeout(), this.redisConfig.getPassword());
    }
}

你好:我的2025